天天看點

【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中釋出、訂閱、觸發事件