遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

.Net事件&委托备忘

委托

public delegate xxxx 定义会生成一个委托类的定义,
该类的主要属性是MethodInfo,Target(当Method是静太方法时Target为null)
对委托的执行是通过MethodInfo.Invoke进行反射调用.
该类继承自MulticastDelegate而MulticastDelegate又继承自Delegate
Delegate定义了Combine与Remove两个操作,这两个操作的具体实现是在MulticastDelegate中,MulticastDelegate采用链表形式保留委托链,事件本质上就是对委托的封装

 

事件可以使用两种方式定义

public delegate void EventHandle()

1.声明方式

public event EventHandle Click

 

2.属性方式

private static object Event_Click=new object();

public event Click

{

   add{...}

   remove{...}

}
说明

第一种方式编译后形成如下类似的代码

private EventHandle _Click

public event EventHandle Click

{

  add

  {...
     _Click=Delegate.Combine(ad2, value);
.....

   }

  remove

  {
  ....
   _Click=Delegate.Remove(ad2, value);
  ....

  }

}

 

复制代码
    private EventHandler SomeEvent1;

    // Events
    public event EventHandler SomeEvent
    {
        add
        {
            EventHandler handler2;
            EventHandler someEvent = this.SomeEvent1;
            do
            {
                handler2 = someEvent;
                EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value);
                someEvent = Interlocked.CompareExchange<EventHandler>(ref this.SomeEvent1, handler3, handler2);
            }
            while (someEvent != handler2);
        }
        remove
        {
            EventHandler handler2;
            EventHandler someEvent = this.SomeEvent1;
            do
            {
                handler2 = someEvent;
                EventHandler handler3 = (EventHandler) Delegate.Remove(handler2, value);
                someEvent = Interlocked.CompareExchange<EventHandler>(ref this.SomeEvent1, handler3, handler2);
            }
            while (someEvent != handler2);
        }
    }
View Code
复制代码

上面的代码do{}while(..)是考虑并发时确保每对this.SomeEvent1附值串行进行,Interlocked.c(v0,v1,v2) 会比较v0是否等于v2,如果相等(即进行Combin后this.SomeEvent1没有被其他线程绑定过), 则将v1附值给v0

否则重新绑定,不管v0是否等于v2 interlocked.cxx(v0,v1,v2) 反回的是原v0的值(v0的旧值)

 

第二种方式内部使用EventHandleList保存,EventHandleList实质上是一个链表实现,在EventHandleList的实现中,绑定到不同事件的处理过程通过key来检索,
绑定到同一个事件的处理过程还是使用委托链来保存.

为什么说使用属性方式实现比较节省内存
原因在于使用属性方式时,定义的key是private static object Eventxxx=new object(); 该字段使用的是static,这样当该组件/控件被大量实例化时他们只使用同一个对象(当然每个实例有一个自己的EventHandleList),而采用声明方式定义时每个实例都会有一组private EventHandle xxx 字段,而每个字段占用4个字节,当组件/控件有大量事件并创建很多实例时(参考下面winform截图),其内存消耗势必比使用属性方式多,

参考资料:

C# 委托链,Delegate.Combine与Delegate.Remove 深究。
也谈事件(Event)
NET 相关问题: 事件存取器
http://www.cnblogs.com/artech/tag/Event/
事件与委托有别, delegate 与 Delegate 相异
EventHandlerList类型内部存储示意图
C#综合揭秘——深入分析委托与事件
http://topic.csdn.net/u/20090710/10/695cf504-f558-425b-b728-723b6d9232ab.html

 

posted on   遗忘海岸  阅读(360)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
历史上的今天:
2008-09-04 T-SQL 选择某一记录的前后相关记录
点击右上角即可分享
微信分享提示