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

时间:2014-02-24 12:17:15

标签: c#

我正在看这个模式的函数:

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的正文中的括号样式)不会被编译器优化掉。我不明白为什么这会是编译器无法解决的性能问题。

4 个答案:

答案 0 :(得分:3)

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

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();
}

此时我认为您可以同意,纯粹为了清晰起见,程序员修改代码会更好。在这一点上,如果代码更好地编写,其他方式更有效,更清晰,实现优化的重点是什么?

答案 1 :(得分:2)

经过一番搜索:答案在warning description

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

()

您实际上正在进行两次演员,因为Derived d = new Derived(); Base b = d as Base; if (b != null) { Console.WriteLine(b.ToString()); } 也在执行强制转换操作。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

  

我被问到“为什么C#不实现功能X?”每时每刻。答案总是一样的:因为没有人设计,指定,实施,测试,记录和发送该功能。所有这六件事都是实现这一功能所必需的。所有这些都耗费了大量的时间,精力和金钱。功能并不便宜,我们非常努力地确保我们只提供那些能够为我们的用户提供最佳利益的功能,因为我们的时间,精力和预算都有限。