天天看点

【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

            call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)

        //发布事件

        .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        

        {                        

            //触发事件

            ldnull

            ceq

            brtrue.s L_001

            callvirt instance void [ESBasic]ESBasic.CbSimple::Invoke()

            nop

     L_001: ret            

    }

}   

再看ComputerManager实现:

    .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

               ldc.i4.0

               stfld int32 ILTest.ComputerManager::handleCount

               //调用基类ctor

                call instance void [mscorlib]System.Object::.ctor()                

                //预定事件

               ldfld class [ILTest]ILTest.Computer [ILTest]ILTest.ComputerManager::computer

               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

            ldfld int32 ILTest.ComputerManager::handleCount

            ldc.i4.1

            add

            stfld int32 ILTest.ComputerManager::handleCount            

        }      

        .method public hidebysig instance int32 GetHandleCount() cil managed

        }        

}

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

    .class private auto ansi beforefieldinit MainClass

        .method public hidebysig static void Main(string[] args) cil managed

            .entrypoint

            .locals init 

              (                  

                  [0] class [ILTest]ILTest.Computer computer,

                  [1] class [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的代码提示),截图如下:

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