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

     

 

时间: 2024-08-01 03:49:39

【Emit基础】IL中发布、订阅、触发事件的相关文章

JavaScript中发布/订阅模式的简单实例

 1.Observer模式要求希望接收到主题通知者的观察者必须订阅内容改变的事件. 2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间.该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值.其目的是避免订阅者和发布者产生依赖关系. 与Observer模式不同之处在于它允许任何订阅者执行适当的事件处理程序来注册和接收发布者发出的通知. 好吧,不明觉厉.下面是我的理解: 1.观察者模式中,目标对象负责维护观

JavaScript中发布/订阅模式的简单实例_javascript技巧

上次研究观察者模式,很多文章说它也叫Subscribe/Publish(发布/订阅模式).可在<Javascript设计模式>一书中,这两种模式还是有些区别的.书中原话如下: 1.Observer模式要求希望接收到主题通知者的观察者必须订阅内容改变的事件. 2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间.该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值.其目的是避免订阅者和发布者产生依赖关系.

Redis基础知识 之——发布/订阅

一.说明:        订阅,取消订阅和发布实现了发布/订阅消息范式(引自wikipedia),发送者(发布者)不是计划发送消息给特定的接收者(订阅者).而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅.订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的.这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑. 二.发布及订阅功能: 基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求

Ext中的面板触发事件时怎么替换?

问题描述 var Panel1= new Ext.Panel({//面板1 region : 'center', layout: 'fit', items: [mdmList] }); var Panel2= new Ext.Panel({//面板2 region : 'center', layout: 'fit', items: [casesList] }); 触发一个事件时,把原有的panel1替换为panel2~ 解决方案 为什么要换组件呢?用CardLayout不好吗?var panel

c#-C#DataGridview双击触发事件

问题描述 C#DataGridview双击触发事件 在DataGridview中,双击触发事件.该怎么写..doblue chilk 属性在哪找. 解决方案 在vs中右键datagridview控件,事件中有很多,找找包含double字样的事件. 比如:dataGridView1_CellDoubleClick.dataGridView1_CellMouseDoubleClick 等等 解决方案二: Gridview控件那么多事件,你可以找找看 解决方案三: 没有这个属性,你可以通过脚本触发双击

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

     本文通过一个简单的示例来说明在IL中进行异常处理时要注意的关键点.      我们来看一个包含try...catch...finally的示例:         public void TestEF()         {                       TransactionScopeFactory factory = new TransactionScopeFactory(null);             TransactionScope scope = facto

从零开始学_JavaScript_系列(九)——dojo(2)(AJAX、时间控件、鼠标事件、样式修改、事件移除、消息发布订阅)

如果没有接触过dojo,建议阅读: http://blog.csdn.net/qq20004604/article/details/51028702 里面介绍了如何加载dojo. 关于dojo的下载,请查看: https://dojotoolkit.org/download/ 建议下载FULL SOURCE版 如果需要讨论,请评论.或者站内信,我会尽快回复. (21)和(22)写的不好,跳过. (23)AJAX异步加载 插件:dojo/request 参数:request 语法(get): re

Spread for Windows Forms快速入门(8)---单元格中用户动作触发的事件

这篇文章概括介绍了单元格的哪些事件是由控件的用户动作触发的.虽然它没有全面地列出的用户可能执行的每一个动作,但是它详细地描述了用户所使用的大部分普通操作所引发的事件. 因为某些动作一直出现,或者某些动作反复出现, 我们就在列表中放弃了这部分动作.举例来说,这些列表并不包括MouseMove, MouseHover, MouseEnter, MouseLeave, Invalidated和CursorChanged事件. 如果你想在此基础上做进一步的研究,我们提供了一个示例以便你与Spread控件

在C#中使用代理的方式触发事件

事件(event)是一个非常重要的概念,我们的程序时刻都在触发和接收着各种事件:鼠标点击事件,键盘事件,以及处理操作系统的各种事件.所谓事件就是由某个对象发出的消息.比如用户按下了某个按钮,某个文件发生了改变,socket上有数据到达.触发事件的对象称作发送者(sender),捕获事件并且做出响应的对象称作接收者(receiver),一个事件可以存在多个接受者. 在异步机制中,事件是线程之间进行通信的一个非常常用的方式.比如:用户在界面上按下一个按钮,执行某项耗时的任务.程序此时启动一个线程来处