Throw VS rethrow : same result?

前端 未结 5 1736
隐瞒了意图╮
隐瞒了意图╮ 2021-02-20 11:26

refering to a lot of documentation on the net, particularly on SO, eg : What is the proper way to re-throw an exception in C#? there should be a difference between \"throw e;\"

5条回答
  •  庸人自扰
    2021-02-20 11:52

    It seems that the JIT optimizers does some work here. As you can see, the call stack in the second case is different than in the first case when you run the Debug build. However, in the Release build, both call stacks are identical due to the optimization.

    To see that this is related to the jitter you can decorate the methods with a MethodImplAttribute attribute:

    [MethodImpl(MethodImplOptions.NoOptimization)]
    private static void ThrowWithoutVariable()
    {
        try
        {
            BadGuy();
        }
        catch
        {
            throw;
        }
    }
    

    Note that the IL is still different for ThrowWithoutVariable and ThrowWithVariable:

    .method private hidebysig static void  ThrowWithVariable() cil managed
    {
      // Code size       11 (0xb)
      .maxstack  1
      .locals init ([0] class [mscorlib]System.Exception ex)
      .try
      {
        IL_0000:  call       void Ex::BadGuy()
        IL_0005:  leave.s    IL_000a
      }  // end .try
      catch [mscorlib]System.Exception 
      {
        IL_0007:  stloc.0
        IL_0008:  ldloc.0
        IL_0009:  throw
      }  // end handler
      IL_000a:  ret
    } // end of method Ex::ThrowWithVariable
    
    .method private hidebysig static void  ThrowWithoutVariable() cil managed
    {
      // Code size       11 (0xb)
      .maxstack  1
      .try
      {
        IL_0000:  call       void Ex::BadGuy()
        IL_0005:  leave.s    IL_000a
      }  // end .try
      catch [mscorlib]System.Object 
      {
        IL_0007:  pop
        IL_0008:  rethrow
      }  // end handler
      IL_000a:  ret
    } // end of method Ex::ThrowWithoutVariable
    

    Update to answer your follow-up question whether this is compliant with the CLI specification

    In fact it compliant, namely to allow for the JIT compiler to enable important optimizations. Annex F states on page 52 (emphasis by me):

    Some CIL instructions perform implicit run-time checks that ensure memory and type safety. Originally, the CLI guaranteed that exceptions were precise, meaning that program state was preserved when an exception was thrown. However, enforcing precise exceptions for implicit checks makes some important optimizations practically impossible to apply. Programmers can now declare, via a custom attribute, that a method is “relaxed”, which says that exceptions arising from implicit run-time checks need not be precise.

    Relaxed checks preserve verifiability (by preserving memory and type safety) while permitting optimizations that reorder instructions. In particular, it enables the following optimizations:

    • Hoisting implicit run-time checks out of loops.
    • Reordering loop iterations (e.g., vectorization and automatic multithreading)
    • Interchanging loops
    • Inlining that makes an inlined method as least as fast as the equivalent macro

提交回复
热议问题