Home >Backend Development >C#.Net Tutorial >C# exception handling (Catch Throw) IL analysis
1. Several forms and performance impacts of catch throw:
private void Form1_Click(object sender, EventArgs e) { try { } catch { throw; } } private void Form1_Load(object sender, EventArgs e) { try { } catch (Exception) { throw; } } private void Form1_Enter(object sender, EventArgs e) { try { } catch (Exception ee) { throw; } } private void Form1_DoubleClick(object sender, EventArgs e) { try { } catch (Exception ee) { throw ee; } }
Corresponding IL code (the following code is the IL code of the release version):
.method private hidebysig instance void Form1_Click(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Form1::Form1_Click .method private hidebysig instance void Form1_Load(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Form1::Form1_Load .method private hidebysig instance void Form1_Enter(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 1 (0x1) .maxstack 8 IL_0000: ret } // end of method Form1::Form1_Enter .method private hidebysig instance void Form1_DoubleClick(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 1 (0x1) .maxstack 1 .locals init ([0] class [mscorlib]System.Exception ee) IL_0000: ret } // end of method Form1::Form1_DoubleClick
You can see Form1_Click, The try catch in Form1_Load and Form1_Enter has been optimized by the compiler:
IL_0000: ret //即为 return 标记 返回值
Only the try catch in Form1_DoubleClick is processed:
.locals init ([0] class [mscorlib]System.Exception ee) //定义 Exception 类型参数 ee (此时已经把ee存入了Call Stack中)
That is, the try catch in Form1_DoubleClick will have an impact on performance.
==》You can see that the three ways of writing try catch are exactly the same for the release version of the code, and will not cause any performance consumption:
try { } catch { throw; } try { } catch (Exception) { throw; } try { } catch (Exception ee) { throw; }
You can write a test demo to verify the above conclusion (tested, the results are consistent with the analysis).
##So what does the IL code in debug mode look like?
.method private hidebysig instance void Form1_Click(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 11 (0xb) .maxstack 1 IL_0000: nop .try { IL_0001: nop IL_0002: nop IL_0003: leave.s IL_0009 } // end .try catch [mscorlib]System.Object { IL_0005: pop IL_0006: nop IL_0007: rethrow } // end handler IL_0009: nop IL_000a: ret } // end of method Form1::Form1_Click .method private hidebysig instance void Form1_Load(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 11 (0xb) .maxstack 1 IL_0000: nop .try { IL_0001: nop IL_0002: nop IL_0003: leave.s IL_0009 } // end .try catch [mscorlib]System.Exception { IL_0005: pop IL_0006: nop IL_0007: rethrow } // end handler IL_0009: nop IL_000a: ret } // end of method Form1::Form1_Load .method private hidebysig instance void Form1_Enter(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 11 (0xb) .maxstack 1 .locals init ([0] class [mscorlib]System.Exception ee) IL_0000: nop .try { IL_0001: nop IL_0002: nop IL_0003: leave.s IL_0009 } // end .try catch [mscorlib]System.Exception { IL_0005: stloc.0 IL_0006: nop IL_0007: rethrow } // end handler IL_0009: nop IL_000a: ret } // end of method Form1::Form1_Enter .method private hidebysig instance void Form1_DoubleClick(object sender, class [mscorlib]System.EventArgs e) cil managed { // 代码大小 11 (0xb) .maxstack 1 .locals init ([0] class [mscorlib]System.Exception ee) IL_0000: nop .try { IL_0001: nop IL_0002: nop IL_0003: leave.s IL_0009 } // end .try catch [mscorlib]System.Exception { IL_0005: stloc.0 IL_0006: nop IL_0007: ldloc.0 IL_0008: throw } // end handler IL_0009: nop IL_000a: ret } // end of method Form1::Form1_DoubleClick
It can be seen that the only difference between the four writing methods in debug mode is: the difference between rethrow and throw. What do rethrow and throw stand for in IL?
Throw: Throws the exception object currently on the calculation stack.
Rethrow: Rethrow the current exception.
That is, When we throw an exception, the CLR will reset an exception starting point. The CLR only records the location of the most recent exception thrown. The following code throws an exception, causing the CLR to reset the starting point of the exception:
## try
{
//一些处理
}
catch (Exception e)
{
//一些处理
throw e; //CLR认为这里是异常的起始点
}
Instead , if we throw an exception object, the CLR will not reset the starting point of its stack. The following code throws an exception, but will not cause the CLR to reset the starting point of the exception:
try
{
//一些处理
}
catch (Exception e)
{
//一些处理
throw; //CLR不会重新设置异常的起始点
}
In C#, throw and throw ex are used to throw exceptions, but there is a difference between the two.
It is recommended to use throw; to throw exceptions in C#; throw ex; will clear all the information so far, thinking that the exception you caught has been It was processed, but a new exception was thrown during the processing, so the real source of the error could not be found.
throw e rethrows the exception, which does not forward the original exception, but changes many exception internal information including StackTrace; for the case of deep call connection, performance loss Beyond imagination.
The above is the content of C# exception handling (Catch Throw) IL analysis. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!