C#编译器优化 - 仅包含throw的Catch

时间:2014-08-21 06:16:26

标签: c# try-catch compiler-optimization

我希望以下两个MyMethod的实现行为完全相同。他们呢?如果没有,这可能是我错误的假设:

首先:

public int MyMethod(int x)
{
    try
    {
        return x + 8;
    }
    catch
    {
        throw;
    }
}

第二

public int MyMethod(int x)
{
    return x + 8;
}

所以,我认为编译器会优化它,即删除第一个实现的不必要的try / catch块(当处于释放模式时)。 事实证明,它没有 - 这是两个代码样本生成的IL:

首先:

.method public hidebysig instance int32  MyMethod(int32 x) cil managed
{
  // Code size       11 (0xb)
  .maxstack  2
  .locals init ([0] int32 CS$1$0000)
  .try
  {
    IL_0000:  ldarg.1
    IL_0001:  ldc.i4.8
    IL_0002:  add
    IL_0003:  stloc.0
    IL_0004:  leave.s    IL_0009
  }  // end .try
  catch [mscorlib]System.Object 
  {
    IL_0006:  pop
    IL_0007:  rethrow
  }  // end handler
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method MyClass::MyMethod

第二

.method public hidebysig instance int32  MyMethod(int32 x) cil managed
{
  // Code size       4 (0x4)
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  ldc.i4.8
  IL_0002:  add
  IL_0003:  ret
} // end of method MyClass::MyMethod

有人可以对此有所了解吗?这两种实现的行为是否存在相关差异(副作用?)?编译器可以优化代码,但不是吗?谢谢!

2 个答案:

答案 0 :(得分:2)

大多数优化都是由JITter完成的,只有编译器生成IL才进行一些优化。所以我无法分辨在程序运行期间实际编译成机器代码的是什么(尽管你可以调试) 您可以在帖子中找到信息:http://blogs.msdn.com/b/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do.aspx由一个c#编译器团队编写 它说:
“/ optimize标志不会改变我们的大量发射和生成逻辑。我们总是尝试生成简单,可验证的代码,然后依靠抖动在生成真实机器代码时进行大量优化”

您还可以在链接上找到有关为生成IL代码而实际优化的一些案例的信息。

更新

对答案的含义进行了性能测试:
what will empty catch and throw block do?
它证实它没有被优化掉。

关于是否可以删除代码的问题,有一个讨论: Can I remove empty catch with throw?

答案 1 :(得分:0)

编译器不能假设在这种情况下不需要try / catch块。

如果里面有任何代码,则可能会抛出异常。 例如:

  • " +"可以在其中一个对象中覆盖运算符并抛出一个 例外......
  • 将从"#34;返回的对象的构造函数block可以抛出异常......

即使你不是"处理"在" catch"中捕获的异常对象声明,很多事情都发生在后台。例如,启动Exception对象的构造函数(编译器无法确定是否存在重要的实现)。

正如你所看到的那样,从编译器的角度来看,即使是单个(几乎是空的)try / catch块也不是那么简单。