【Emit基础】在IL中进行异常处理

简介: 本文通过一个简单的示例来说明在IL中进行异常处理时要注意的关键点。      我们来看一个包含try...catch...finally的示例:         public void TestEF()         {                       Transa...

     本文通过一个简单的示例来说明在IL中进行异常处理时要注意的关键点。

     我们来看一个包含try...catch...finally的示例:

        public   void  TestEF()
        {          
            TransactionScopeFactory factory 
=   new  TransactionScopeFactory( null );
            TransactionScope scope 
=  factory.NewTransactionScope( false );

            
try
            {                
                scope.Commit();
            }
            
catch  (Exception ee)
            {
                
string  msg  =  ee.Message;
            }
            
finally
            {
                scope.Dispose();
            }
        }

     这段代码实际上与使用using是等价的:

public   void  TestEF()
{
    TransactionScopeFactory factory 
=   new  TransactionScopeFactory( null );
    
using  (TransactionScope scope  =  factory.NewTransactionScope( false ))
    {
        
try
        {
            scope.Commit();
        }
        
catch  (Exception ee)
        {
            
string  msg  =  ee.Message;
        }
    }
}

     它们对应的IL代码如下所示:

.method  public  hidebysig instance  void  TestEF() cil managed
{
    .maxstack 
2
    .locals init (
        [
0 class  [DataRabbit.Application]DataRabbit.Application.TransactionScopeFactory factory,
        [
1 class  [DataRabbit.Application]DataRabbit.Application.TransactionScope scope,
        [
2 class  [mscorlib]System.Exception ee,
        [
3 string  msg)
    L_0000: nop 
    L_0001: ldnull 
    L_0002: newobj instance 
void  [DataRabbit.Application]DataRabbit.Application.TransactionScopeFactory::.ctor( class  [DataRabbit]DataRabbit.DataConfiguration)
    L_0007: stloc.
0  
    L_0008: ldloc.
0  
    L_0009: ldc.i4.
0  
    L_000a: callvirt instance 
class  [DataRabbit.Application]DataRabbit.Application.TransactionScope [DataRabbit.Application]DataRabbit.Application.TransactionScopeFactory::NewTransactionScope( bool )
    L_000f: stloc.
1  
    L_0010: nop 
    L_0011: ldloc.
1  
    L_0012: callvirt instance 
void  [DataRabbit.Application]DataRabbit.Application.TransactionScope::Commit()
    L_0017: nop 
    L_0018: nop 
    L_0019: leave.s L_0027
    L_001b: stloc.
2  
    L_001c: nop 
    L_001d: ldloc.
2  
    L_001e: callvirt instance 
string  [mscorlib]System.Exception::get_Message()
    L_0023: stloc.
3  
    L_0024: nop 
    L_0025: leave.s L_0027
    L_0027: nop 
    L_0028: leave.s L_0034
    L_002a: nop 
    L_002b: ldloc.
1  
    L_002c: callvirt instance 
void  [DataRabbit.Application]DataRabbit.Application.TransactionScope::Dispose()
    L_0031: nop 
    L_0032: nop 
    L_0033: endfinally 
    L_0034: nop 
    L_0035: ret 
    .
try L_0010 to L_001b catch  [mscorlib]System.Exception handler L_001b to L_0027
    .
try L_0010 to L_002a finally  handler L_002a to L_0034
}

 

     我们来剖析这段IL中的异常处理流程:

1.有最后的两句代码,我们看到:

(1)try...catch...finally 是由try...catch 和 try...finally两部分构成。

(2)try...finally 中的try块内含了catch块。

即类似这样:

           .try
              
{
                  .
try
                  {
                  }
                  
catch
                  {
                  }
              }
              
finally
              {
              }

 

2.try块、catch块(catch handler)只能通过leave(或leave.s)退出。

3.finally块(finally handler)必须通过endfinally退出。

4.由于try...catch 和 try...finally两部分都需要退出try块,所以我们看到在L_0019 和 L_0028 处都有对应的leave.s指令。

5.程序中如果没有finally块,则IL中只需要处理try...catch 部分;同理,如果程序中没有catch块,则IL只需要处理try...finally部分。

6.总结起来,IL的异常处理类似这个样子:

           .try
              
{
                  .
try
                  {

                         leave L1
                  }
                  
catch
                  {

                         leave L1
                  }

                  leave L2

              }
              
finally
              {

                    endfinally
              }

 

 

 

 

目录
相关文章
|
6月前
|
JavaScript 前端开发 开发者
JavaScript中的错误处理:try-catch语句与错误对象
【4月更文挑战第22天】JavaScript中的错误处理通过try-catch语句和错误对象实现。try块包含可能抛出异常的代码,catch块捕获并处理错误,finally块则无论是否出错都会执行。错误对象提供关于错误的详细信息,如类型、消息和堆栈。常见的错误类型包括RangeError、ReferenceError等。最佳实践包括及时捕获错误、提供有用信息、不忽略错误、利用堆栈信息和避免在finally块中抛错。
|
存储 Go Python
Go-动态类型与类型断言详解(含type-switch及全部代码)
Go-动态类型与类型断言详解(含type-switch及全部代码)
121 0
Go-动态类型与类型断言详解(含type-switch及全部代码)
|
Java API C#
C#反射与特性(十):EMIT构建代码
C#反射与特性(十):EMIT构建代码
273 0
异常处理:消极处理 一般是在函数中 raise 异常类
异常处理:消极处理 一般是在函数中 raise 异常类
|
JavaScript 前端开发 开发者
JavaScript基础之五——异常的抛出与捕获
JavaScript基础之五——异常的抛出与捕获
127 0
|
前端开发 开发者
剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类
本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,建议先了解Promise的使用 Promise标准解读 1.
761 0