C#之旅(三): 显式实现事件
把《CLR VIA C#》又翻出来看了一下,看到11.4节的“显式实现事件”又有所领悟。当忙于项目进度的时候基本没什么时间可以静下心来翻阅下书籍,而只有经过项目的实战在回过头来去看些基础的知识,忽然会有种水到渠成的感觉。
起初看到这个标题“显式实现事件”时我错误的当成了是显式实现接口了,看完之后才明白怎么回事,跟接口本就没半点的关系。原来显式实现事件就是为事件添加一个属性(add、remove)访问器。为什么要这么麻烦呢?在类里面添加事件不都这样的么:public event EventHandler myevent;有几个事件需要发布就写几行这样的代码,其它的工作编译器都会替我们解决了。但问题也就在于此,编译器会为event类型生成一个委托类型(这里是EventHandler)的实例字段,同时会生成两个方法:add_Xxx和remove_Xxx。假如事件数量很多,比如System.Windows.Forms.Control 类事件有70来个,要是以这种方式那么实例化一个Control对象就必须生成70多个委托类型的示例字段,这样的开销无疑是很大的。因此微软为了减少开销采取的方法就是“显式实现事件”。
这里就有必要提下:EventHandlerList 提供一个简单的委托列表。从Control的基类Component可以看到它的定义 private EventHandlerList events;Control类会为每一个事件添加一个静态私有字段来作为Key->delegate映射保存到EventHandlerList 这个集合中来,作为Key的静态字段会在静态构造函数里进行实例化。调用事件的add访问器添加事件时先去events查找当前的Key值是否存在:存在就将事件添加到对应的委托链里面;不存在则添加Key->delegate的映射。
作为Key的定义:
2 private static readonly object EventBackColor;
3 private static readonly object EventBackgroundImage;
4 private static readonly object EventBackgroundImageLayout;
5 private static readonly object EventBindingContext;
6 private static readonly object EventCausesValidation;
7 private static readonly object EventChangeUICues;
8 private static readonly object EventClick;
9 private static readonly object EventClientSize;
10 private static readonly object EventContextMenu;
11 private static readonly object EventContextMenuStrip;
12 private static readonly object EventControlAdded;
13 private static readonly object EventControlRemoved;
14 private static readonly object EventCursor;
15 private static readonly object EventDock;
16 private static readonly object EventDoubleClick;
17 private static readonly object EventDragDrop;
显式实现事件:
2 {
3 add
4 {
5 base.Events.AddHandler(EventClick, value);
6 }
7 remove
8 {
9 base.Events.RemoveHandler(EventClick, value);
10 }
11 }
12
13 ........
14
EventHandlerList的定义:
2 {
3 // Fields
4 private ListEntry head;
5 private Component parent;
6
7 // Methods
8 public EventHandlerList()
9 {
10 }
11
12 internal EventHandlerList(Component parent)
13 {
14 this.parent = parent;
15 }
16
17 public void AddHandler(object key, Delegate value)
18 {
19 ListEntry entry = this.Find(key);
20 if (entry != null)
21 {
22 entry.handler = Delegate.Combine(entry.handler, value);
23 }
24 else
25 {
26 this.head = new ListEntry(key, value, this.head);
27 }
28 }
29
30 public void AddHandlers(EventHandlerList listToAddFrom)
31 {
32 for (ListEntry entry = listToAddFrom.head; entry != null; entry = entry.next)
33 {
34 this.AddHandler(entry.key, entry.handler);
35 }
36 }
37
38 public void Dispose()
39 {
40 this.head = null;
41 }
42
43 private ListEntry Find(object key)
44 {
45 ListEntry head = this.head;
46 while (head != null)
47 {
48 if (head.key == key)
49 {
50 return head;
51 }
52 head = head.next;
53 }
54 return head;
55 }
56
57 public void RemoveHandler(object key, Delegate value)
58 {
59 ListEntry entry = this.Find(key);
60 if (entry != null)
61 {
62 entry.handler = Delegate.Remove(entry.handler, value);
63 }
64 }
65
66 // Properties
67 public Delegate this[object key]
68 {
69 get
70 {
71 ListEntry entry = null;
72 if ((this.parent == null) || this.parent.CanRaiseEventsInternal)
73 {
74 entry = this.Find(key);
75 }
76 if (entry != null)
77 {
78 return entry.handler;
79 }
80 return null;
81 }
82 set
83 {
84 ListEntry entry = this.Find(key);
85 if (entry != null)
86 {
87 entry.handler = value;
88 }
89 else
90 {
91 this.head = new ListEntry(key, value, this.head);
92 }
93 }
94 }
95
96 // Nested Types
97 private sealed class ListEntry
98 {
99 // Fields
100 internal Delegate handler;
101 internal object key;
102 internal EventHandlerList.ListEntry next;
103
104 // Methods
105 public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next)
106 {
107 this.next = next;
108 this.key = key;
109 this.handler = handler;
110 }
111 }