遗忘海岸

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

导航

.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 2012-09-04 14:49  遗忘海岸  阅读(354)  评论(0编辑  收藏  举报