C# Delegates And Events in Depth[翻译加笔记]【Event】【2】
2011-08-15 06:52 一一九九 阅读(373) 评论(0) 编辑 收藏 举报http://www.ikriv.com/en/prog/info/dotnet/Delegates.html
Events
概念上, Event是一对方法: Add accessor 和Remove accessor. 每一个方法都接受一个具体的Delegate Type的参数。Add accessor 通过 “e+ = d”来调用,remove accessor 通过 “e-=d”来调用。
Event可以被明确的如下声明:
class MyClass
{public event MyDelegate GoodNews{add{// add accessor code here
}remove{// remove accessor code here
}}}
Event有点像delegate(实际上不是),比如同时有add和remove两个accessor.
注意Event 并没有提供一个调用或者激发的方法。这是因为在生命的Class外部,Event是不能被激活的,也就是说,Event并不提供激发的接口,仅仅是一个实现的细节。
Using Events
只能通过+=和-=来订阅和取消时间。如何来计划是由Class的作者来决定的。
Implementing Events
自己定义的实现方式如下所示:
class MyClass
{public event MyDelegate GoodNews{add{lock(this){_goodNews += value;
}}remove{lock(this){_goodNews -= value;
}}}private void OnGoodNews(){if (_goodNews != null){_goodNews();}}private MyDelegate _goodNews;
}
这种实现方式并不是唯一的一种实现方式。让我们考虑另外一种情况,加入我们的类定义了很多的Event, 而且只有若干个Event实际上被某个类的实例来Hook Up的,在这种情况下,存储大量的私有的Delegate变量将会浪费很多的空间,每一个类的实例都会保存所有的Delegates, 并且只有少数几个才能够被使用。对于这种情况的解决方式是在每一个实例中设置一个Container来存储实际上使用的Delegates. 很多Control就是这样的实现的。
反编译Control单元,可以看到如下的一段话:
[SRDescription("ControlOnBackColorChangedDescr"), SRCategory("CatPropertyChanged")]public event EventHandler BackColorChanged{add{base.Events.AddHandler(EventBackColor, value);}remove{base.Events.RemoveHandler(EventBackColor, value);}}[SRDescription("ControlOnBackgroundImageChangedDescr"), SRCategory("CatPropertyChanged")]public event EventHandler BackgroundImageChanged{add{base.Events.AddHandler(EventBackgroundImage, value);}remove{base.Events.RemoveHandler(EventBackgroundImage, value);}}
而Events是一个EventHandlerList。
protected EventHandlerList Events
{get
{if (this.events == null){this.events = new EventHandlerList(this);}return this.events;}}
访问的时候是通过如下的方式来访问的:
[EditorBrowsable(EditorBrowsableState.Advanced)]protected virtual void OnDockChanged(EventArgs e){EventHandler handler = base.Events[EventDock] as EventHandler;if (handler != null){handler(this, e);
}}
其内部定义了一个默认的数组值来处理:
private static readonly object EventDock;
EventHandlerList的代码如下,这是个Hash类似的结构:
[HostProtection(SecurityAction.LinkDemand, SharedState=true)]
public sealed class EventHandlerList : IDisposable{// Fields
private ListEntry head;
private Component parent;
// Methods
public EventHandlerList();
internal EventHandlerList(Component parent);
public void AddHandler(object key, Delegate value);public void AddHandlers(EventHandlerList listToAddFrom);public void Dispose();private ListEntry Find(object key);public void RemoveHandler(object key, Delegate value);// Properties
public Delegate this[object key] { get; set; }// Nested Types
private sealed class ListEntry{// Fields
internal Delegate handler;
internal object key;internal EventHandlerList.ListEntry next;
// Methods
public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next);}}
Field-like Events
编译器在默认的Event声明后面自动的生成默认的accessors,添加了一个匿名的私有字段来存储要激活的List。所以此时如果继承一个Class,想要访问父类中的Event是访问不到的。
可以将Event声明为Virtual方式的供子类调用。