【Emit基础】IL中发布、订阅、触发事件

     在下面的例子中,我定义了一个事件发布类Computer,事件订阅者ComputerManager。Computer发布了一个OnAction事件,并且该事件在Increase方法被调用时触发。ComputerManager接收到事件通知时,会将成员字段handleCount增加1.

     先看Computer的定义:

.namespace ILTest
{
    .
class public auto ansi beforefieldinit Computer extends [mscorlib]System.Object
    {        
              
      
   //事件对应的委托实例
        .field private class [ESBasic]ESBasic.CbSimple onAction 
        
        
//订阅事件
        .method public hidebysig specialname instance void add_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
        {
            ldarg.
0
            dup
            ldfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            ldarg.
1
            call 
class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
            castclass [ESBasic]ESBasic.CbSimple
            stfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            
            ret
        }
        
        
//取消订阅
        .method public hidebysig specialname instance void remove_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
        {
            ldarg.
0
            dup
            ldfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            ldarg.
1
            call 
class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
            castclass [ESBasic]ESBasic.CbSimple
            stfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            
            ret
        }
        
        
//发布事件
        .event [ESBasic]ESBasic.CbSimple OnAction  
        {
            .addon instance 
void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)
            .removeon instance 
void ILTest.Computer::remove_onAction(class [ESBasic]ESBasic.CbSimple)
        }
        
        
        
//*******************  Ctor  **********************************************
        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
           {               
            ldarg.
0 
                call instance 
void [mscorlib]System.Object::.ctor()
                ret 
        }
        
        
        
//*******************  Method  ********************************************
        .method public hidebysig instance void Increase() cil managed        
        {                        
            
//触发事件
            ldarg.0
            ldfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            ldnull
            ceq
            brtrue.s L_001
            ldarg.
0
            ldfld 
class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
            callvirt instance 
void [ESBasic]ESBasic.CbSimple::Invoke()
            nop
            
     L_001: ret            
        }
    }
}   
                  

 

再看ComputerManager实现:

.namespace ILTest
{
    .
class public auto ansi beforefieldinit ComputerManager extends [mscorlib]System.Object
    {
        .field 
private class [ILTest]ILTest.Computer computer
        .field 
private int32 handleCount
        
        .method 
public hidebysig specialname rtspecialname instance void .ctor(class [ILTest]ILTest.Computer) cil managed
           {   
               ldarg.
0
               ldarg.
1
               stfld 
class [ILTest]ILTest.Computer ILTest.ComputerManager::computer
               
               ldarg.
0
               ldc.i4.
0
               stfld int32 ILTest.ComputerManager::handleCount
               
               
//调用基类ctor
            ldarg.0 
                call instance 
void [mscorlib]System.Object::.ctor()                
                
                
//预定事件
               ldarg.0
               ldfld 
class [ILTest]ILTest.Computer [ILTest]ILTest.ComputerManager::computer
               ldarg.
0
               ldftn instance 
void ILTest.ComputerManager::HandleAction()                
               newobj instance 
void [ESBasic]ESBasic.CbSimple::.ctor(object ,native int)//生成委托实例需要两个参数:目标对象和要调用的方法的指针
               callvirt instance void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)    
               
               ret
        }
        
        .method 
public hidebysig instance void HandleAction() cil managed
        {
            ldarg.
0
            dup
            ldfld int32 ILTest.ComputerManager::handleCount
            ldc.i4.
1
            add
            stfld int32 ILTest.ComputerManager::handleCount            
            
            ret
        }      
        
        .method 
public hidebysig instance int32 GetHandleCount() cil managed
        {
            ldarg.
0
            ldfld int32 ILTest.ComputerManager::handleCount
            
            ret
        }        
    }
}

 

最后,我们写个Main方法来测试一下:

.namespace ILTest
{
    .
class private auto ansi beforefieldinit MainClass
    {
        .method 
public hidebysig static void Main(string[] args) cil managed
        {
            .entrypoint
            .locals init 
              (                  
                  [
0class [ILTest]ILTest.Computer computer,
                  [
1class [ILTest]ILTest.ComputerManager computerManager,
                  [
2] int32 count
              )             
            
            newobj instance 
void [ILTest]ILTest.Computer::.ctor()    
            stloc.
0
            ldloc.
0            
            newobj instance 
void [ILTest]ILTest.ComputerManager::.ctor(class [ILTest]ILTest.Computer)    
            stloc.
1
            
            ldloc.
0
               dup
               dup
               call instance 
void [ILTest]ILTest.Computer::Increase()
               call instance 
void
 [ILTest]ILTest.Computer::Increase()
               call instance 
void
 [ILTest]ILTest.Computer::Increase()
            
            ldloc.
1
            call instance int32 [ILTest]ILTest.ComputerManager::GetHandleCount()
            stloc.
2
            ldloca.s 
2            
            call instance 
string [mscorlib]System.Int32::ToString()
            call 
void [mscorlib]System.Console::WriteLine( string )    
            call 
string [mscorlib]System.Console::ReadLine( )
            pop

            ret    
        }
    }
}

     main方法中调用了Increase方法三次,表示OnAction事件将被触发三次,所以运行后输出的结果是3。

 

     如果你想使用IL进行应用程序开发,那么我推荐你使用开发环境SharpDevelop,对IL的支持还是不错的(遗憾的是还不支持对IL的代码提示),截图如下:

     

 

posted @ 2008-09-23 16:47  zhuweisky  阅读(1161)  评论(1编辑  收藏  举报