为什么编译器不将这两个强制转换优化为一个?



我正在查看具有此模式的函数:

if( obj is SpecificClass1 )
{
   ((SpecificClass1)obj).SomeMethod1();
}
else if( obj is SpecificClass2 )
{
   ((SpecificClass2)obj).SomeMethod2();
}
else if( obj is SpecificClass3 )
{
   ((SpecificClass3)obj).SomeMethod3();
}

并获取代码性能分析警告:CA1800 不必要地强制转换。

为什么双转换(在 if 表达式中使用"is"运算符,在每个 if 的主体中使用括号样式转换)没有被编译器优化掉。我不明白为什么这将是编译器无法解决的性能问题。

简单地说,编译器希望你改变:

if( obj is SpecificClass1 )
{
   ((SpecificClass1)obj).SomeMethod1();
}

SpecificClass1 Class1Obj = obj as SpecificClass1;
if (Class1Obj != null)
{
   Class1Obj.SomeMethod1();
}

是的,可以想象编译器可以为您进行转换。但是,我猜编译器团队决定编译器最好发出警告,并要求您进行更改。

想象一下,如果你的原始代码读到:

if( obj is SpecificClass1 )
{
   ((SpecificClass1)obj).SomeMethod1();
   ((SpecificClass1)obj).SomeMethod2();
   ((SpecificClass1)obj).SomeMethod3();
}

在这一点上,我认为您可以同意,纯粹为了清楚起见,最好由程序员修改代码。在这一点上,如果代码以另一种方式编写得更好,恰好更有效、更清晰,那么实施优化的意义何在?

经过一番搜索:答案在警告描述中。

我是对的,在这种情况下,编译器正在寻找as表达式,这将使您免于两个强制转换(is()转换):

Derived d = new Derived();
Base b = d as Base;
if (b != null)
{
  Console.WriteLine(b.ToString());
}

您实际上是在执行两个转换,因为is也在执行转换类型的操作。

优化编译器可以省略第二个强制转换,但这不是必需的,并且 C# 内存模型可能会阻止在许多常见情况下应用此优化。如果始终将首选形式与 as 运算符一起使用,则无论编译器是否实现特殊逻辑来检测和优化这些情况,您都可以获得此"优化"的好处。

引用Eric Lippert(曾经在C#团队工作):

我一直被问到"为什么C#不实现功能X?"。答案总是相同的:因为没有人设计、指定、实现、测试、记录和交付该功能。所有这六件事都是实现功能所必需的。所有这些都花费了大量的时间、精力和金钱。功能并不便宜,我们非常努力地确保我们只提供那些在时间、精力和金钱预算有限的情况下为用户提供最大利益的功能。

最新更新