1

所以前几天我在我们的代码库中遇到了这个小宝石,我想试试看写它的人是否只是懒惰,或者知道一些我不知道的东西。

一个标准的事件处理程序是这样编写的(我会 -

private void OnSomeEvent(IVehicle sender, ISomeArgs args){

 if((sender is Car) && (sender as Car).numWheels == 4 && (sender as Car).hasGas) 
 {
     (sender as Car).drive();
 }

}

我看到这一点,立即想到了许多在这里不必要地进行的拆箱类型转换操作。我就这样改写了——

private void OnSomeEvent(IVehicle sender, ISomeArgs args){


 if (sender is Car){
  Car _car = sender as Car;

   if(_car.numWheels == 4 && _car.hasGas){
     _car.drive();
   }
 }     


}

那么第一个例子知道我不知道的事情吗?编译器是否知道我们正在尝试 多次将类型转换为同一类型并进行一些优化?

4

3 回答 3

1

is使用时不需要,as因为as如果它可以转换为该类型,将返回所需类型的实际对象,否则null返回值。只需检查它null是否是最优化的方式:

private void OnSomeEvent(IVehicle sender, ISomeArgs args){    
   Car _car = sender as Car;
   if(_car != null){
    if(_car.numWheels == 4 && _car.hasGas){
     _car.drive();
    }
   }     
}
于 2013-08-25T15:58:56.430 回答
1

装箱和拆箱仅在值类型和引用类型之间进行。

来自msdn

拆箱是从类型对象到值类型或从接口类型到实现接口的值类型的显式转换。

因此,您的代码中没有任何拆箱。只有一系列类型铸造不会明显影响性能。

于 2013-08-25T16:17:39.153 回答
1

您已经接受了答案,但我已经完成了查找,所以我想我会发布它。

在进行发布构建时检查输出 IL,两种设置之间几乎没有区别。

第一个“未优化”调用的输出 IL 如下所示:

// Code size       47 (0x2f)
.maxstack  8
IL_0000:  ldarg.0
IL_0001:  isinst     TestApp.Program/Car
IL_0006:  brfalse.s  IL_002e
IL_0008:  ldarg.0
IL_0009:  isinst     TestApp.Program/Car
IL_000e:  callvirt   instance int32 TestApp.Program/Car::get_numWheels()
IL_0013:  ldc.i4.4
IL_0014:  bne.un.s   IL_002e
IL_0016:  ldarg.0
IL_0017:  isinst     TestApp.Program/Car
IL_001c:  callvirt   instance bool TestApp.Program/Car::get_hasGas()
IL_0021:  brfalse.s  IL_002e
IL_0023:  ldarg.0
IL_0024:  isinst     TestApp.Program/Car
IL_0029:  callvirt   instance void TestApp.Program/Car::drive()
IL_002e:  ret

第二个“优化”调用的输出 IL 如下所示:

// Code size       34 (0x22)
.maxstack  2
.locals init ([0] class TestApp.Program/Car c)
IL_0000:  ldarg.0
IL_0001:  isinst     TestApp.Program/Car
IL_0006:  stloc.0
IL_0007:  ldloc.0
IL_0008:  brfalse.s  IL_0021
IL_000a:  ldloc.0
IL_000b:  callvirt   instance int32 TestApp.Program/Car::get_numWheels()
IL_0010:  ldc.i4.4
IL_0011:  bne.un.s   IL_0021
IL_0013:  ldloc.0
IL_0014:  callvirt   instance bool TestApp.Program/Car::get_hasGas()
IL_0019:  brfalse.s  IL_0021
IL_001b:  ldloc.0
IL_001c:  callvirt   instance void TestApp.Program/Car::drive()
IL_0021:  ret

在“未优化”调用中进行了额外isinst的调用,这些调用很适合被优化掉,但不会对函数的运行时间产生实质性影响。

也就是说,我仍然会进行“优化”,因为 C# 代码更易于阅读,这比任何性能微优化都更重要(直到您分析代码并确定需要优化性能瓶颈)。

(此外,堆栈稍大一些,但由于它只是一个快速且立即清理的堆栈增加,而且它只有 6 个字节,因此非常小。)

于 2013-08-25T16:24:36.097 回答