前言

事件模块是游戏中很重要的一个模块,而GameFramework的事件模块在网上能找到很多文章,但基本都是讲解其应用方面的,并没有对其源码进行分析。
这里阐述此模块通过如下三个方面:基本的类内信息说明,GF里面存储管理事件的形式,事件抛出和取消订阅的冲突问题。
这里就不用应用举例了,有需要可以查看下面参考文档。

Event模块结构

从上面的结构图也可以看出,EventManager作为事件模块的管理器,其作用主要是对于EventPool的功能进行封装,并提供对应的接口给外部使用。因此本模块的核心逻辑主要在EventPool中。

EventPool

作为事件模块的核心, EventPool处理着事件的发布、订阅、移除等功能的同时也会严格检查事件订阅的匹配情况,不允许出现重复订阅,也不允许出现重复取消订阅或取消订阅尚未订阅的事件处理函数,如果出现这些情况,将会抛出异常。
观察者模式可以从“发布者”和“订阅者”两个角度来看,EventPool里面对应的两个方面便是 “事件” 和 “事件处理函数” 。事件处理函数是订阅者注册给发布者的,一个事件可以包含多个事件处理函数。抛出一个事件,会执行其所有订阅者的事件处理函数。

类内信息

  • 字段功能说明:
    • m_EventHandlers:GF多值字典。key为事件ID,value为事件处理函数的列表,毕竟一个事件可以有多个订阅者,GF是通过多值字典来存储的。
    • m_Events:事件队列。这里的事件(Event)是EventPool中的一个内部类,主要用于记录当前正在抛出的事件。因为其在Update里面执行,可以确保安全性,保证在主线程中回调处理函数,但事件会在抛出后的下一帧分发。
    • m_CachedNotes:事件节点缓存字典。缓存正在抛出的事件节点,用于解决正在抛出事件节点和取消订阅事件节点的冲突问题。通过检测m_CachedNotes里面的数据可以判断当前要取消订阅的事件是否正在被抛出。
    • m_TempNodes:临时事件节点列表。缓存m_CachedNotes里面的节点。在取消订阅的时候,如果当前取消的事件正在被抛出的话,就缓存下一个节点到m_TempNodes,然后给m_cachedNotes里面覆盖赋值,跳过这一个节点的事件派发。
    • m_EventPoolMode:事件池模式。这里的模式主要用于控制事件池的事件处理函数的执行模型,参考EventPoolMode枚举分为四种:
      • Default,默认事件池模式,即必须存在有且只有一个事件处理函数。
      • AllowNoHandler,允许不存在事件处理函数。
      • AllowMultiHandler,允许存在多个事件处理函数。
      • AllowDuplicateHandler,允许存在重复的事件处理函数。
        一般的话使用的是EventPoolMode.AllowNoHandler | EventPoolMode.AllowMultiHandler 这两个模式
    • m_DefaultHandler:默认额外事件处理函数。通过给这个委托赋值,可以设置一个额外的的事件处理函数,当抛出事件后,如果有此委托有内容,就会调用,方便进行拓展。
  • 方法说明:
    • Update:生命周期里轮询方法。这里会检测事件列表里面的事件进行派发,并调用对应的事件处理函数。
    • Shutdown:关闭并清理事件池。
    • Clear:清空当前待处理的事件列表。
    • Count:获取对应事件的事件处理函数的数量。
    • Check:检查对应事件是否存在事件处理函数。
    • Subscribe:订阅事件。
    • Unsubscribe:取消订阅事件。
    • SetDefaultHandler:设置默认额外事件处理函数。
    • Fire和FireNow: 都是抛出事件,Fire会走上面的流程。而FireNow则是立刻执行,这个操作不是线程安全的,但事件会立刻分发。
    • HandleEvent:处理事件和事件函数的核心方法。

EventPool源码如下:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
using System;
using System.Collections.Generic;

namespace GameFramework
{
/// <summary>
/// 事件池。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
internal sealed partial class EventPool<T> where T : BaseEventArgs
{
private readonly GameFrameworkMultiDictionary<int, EventHandler<T>> m_EventHandlers;
private readonly Queue<Event> m_Events;
private readonly Dictionary<object, LinkedListNode<EventHandler<T>>> m_CachedNodes;
private readonly Dictionary<object, LinkedListNode<EventHandler<T>>> m_TempNodes;
private readonly EventPoolMode m_EventPoolMode;
private EventHandler<T> m_DefaultHandler;

/// <summary>
/// 初始化事件池的新实例。
/// </summary>
/// <param name="mode">事件池模式。</param>
public EventPool(EventPoolMode mode)
{
m_EventHandlers = new GameFrameworkMultiDictionary<int, EventHandler<T>>();
m_Events = new Queue<Event>();
m_CachedNodes = new Dictionary<object, LinkedListNode<EventHandler<T>>>();
m_TempNodes = new Dictionary<object, LinkedListNode<EventHandler<T>>>();
m_EventPoolMode = mode;
m_DefaultHandler = null;
}

/// <summary>
/// 获取事件处理函数的数量。
/// </summary>
public int EventHandlerCount
{
get
{
return m_EventHandlers.Count;
}
}

/// <summary>
/// 获取事件数量。
/// </summary>
public int EventCount
{
get
{
return m_Events.Count;
}
}

/// <summary>
/// 事件池轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
public void Update(float elapseSeconds, float realElapseSeconds)
{
while (m_Events.Count > 0)
{
Event eventNode = null;
lock (m_Events)
{
eventNode = m_Events.Dequeue();
HandleEvent(eventNode.Sender, eventNode.EventArgs);
}

ReferencePool.Release(eventNode);
}
}

/// <summary>
/// 关闭并清理事件池。
/// </summary>
public void Shutdown()
{
Clear();
m_EventHandlers.Clear();
m_CachedNodes.Clear();
m_TempNodes.Clear();
m_DefaultHandler = null;
}

/// <summary>
/// 清理事件。
/// </summary>
public void Clear()
{
lock (m_Events)
{
m_Events.Clear();
}
}

/// <summary>
/// 获取事件处理函数的数量。
/// </summary>
/// <param name="id">事件类型编号。</param>
/// <returns>事件处理函数的数量。</returns>
public int Count(int id)
{
GameFrameworkLinkedListRange<EventHandler<T>> range = default(GameFrameworkLinkedListRange<EventHandler<T>>);
if (m_EventHandlers.TryGetValue(id, out range))
{
return range.Count;
}

return 0;
}

/// <summary>
/// 检查是否存在事件处理函数。
/// </summary>
/// <param name="id">事件类型编号。</param>
/// <param name="handler">要检查的事件处理函数。</param>
/// <returns>是否存在事件处理函数。</returns>
public bool Check(int id, EventHandler<T> handler)
{
if (handler == null)
{
throw new GameFrameworkException("Event handler is invalid.");
}

return m_EventHandlers.Contains(id, handler);
}

/// <summary>
/// 订阅事件处理函数。
/// </summary>
/// <param name="id">事件类型编号。</param>
/// <param name="handler">要订阅的事件处理函数。</param>
public void Subscribe(int id, EventHandler<T> handler)
{
if (handler == null)
{
throw new GameFrameworkException("Event handler is invalid.");
}

if (!m_EventHandlers.Contains(id))
{
m_EventHandlers.Add(id, handler);
}
else if ((m_EventPoolMode & EventPoolMode.AllowMultiHandler) != EventPoolMode.AllowMultiHandler)
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow multi handler.", id.ToString()));
}
else if ((m_EventPoolMode & EventPoolMode.AllowDuplicateHandler) != EventPoolMode.AllowDuplicateHandler && Check(id, handler))
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow duplicate handler.", id.ToString()));
}
else
{
m_EventHandlers.Add(id, handler);
}
}

/// <summary>
/// 取消订阅事件处理函数。
/// </summary>
/// <param name="id">事件类型编号。</param>
/// <param name="handler">要取消订阅的事件处理函数。</param>
public void Unsubscribe(int id, EventHandler<T> handler)
{
if (handler == null)
{
throw new GameFrameworkException("Event handler is invalid.");
}

if (m_CachedNodes.Count > 0)
{
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in m_CachedNodes)
{
if (cachedNode.Value != null && cachedNode.Value.Value == handler)
{
m_TempNodes.Add(cachedNode.Key, cachedNode.Value.Next);
}
}

if (m_TempNodes.Count > 0)
{
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in m_TempNodes)
{
m_CachedNodes[cachedNode.Key] = cachedNode.Value;
}

m_TempNodes.Clear();
}
}

if (!m_EventHandlers.Remove(id, handler))
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not exists specified handler.", id.ToString()));
}
}

/// <summary>
/// 设置默认事件处理函数。
/// </summary>
/// <param name="handler">要设置的默认事件处理函数。</param>
public void SetDefaultHandler(EventHandler<T> handler)
{
m_DefaultHandler = handler;
}

/// <summary>
/// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
public void Fire(object sender, T e)
{
if (e == null)
{
throw new GameFrameworkException("Event is invalid.");
}

Event eventNode = Event.Create(sender, e);
lock (m_Events)
{
m_Events.Enqueue(eventNode);
}
}

/// <summary>
/// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
public void FireNow(object sender, T e)
{
if (e == null)
{
throw new GameFrameworkException("Event is invalid.");
}

HandleEvent(sender, e);
}

/// <summary>
/// 处理事件结点。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
private void HandleEvent(object sender, T e)
{
bool noHandlerException = false;
GameFrameworkLinkedListRange<EventHandler<T>> range = default(GameFrameworkLinkedListRange<EventHandler<T>>);
if (m_EventHandlers.TryGetValue(e.Id, out range))
{
LinkedListNode<EventHandler<T>> current = range.First;
while (current != null && current != range.Terminal)
{
m_CachedNodes[e] = current.Next != range.Terminal ? current.Next : null;
current.Value(sender, e);
current = m_CachedNodes[e];
}

m_CachedNodes.Remove(e);
}
else if (m_DefaultHandler != null)
{
m_DefaultHandler(sender, e);
}
else if ((m_EventPoolMode & EventPoolMode.AllowNoHandler) == 0)
{
noHandlerException = true;
}

ReferencePool.Release(e);

if (noHandlerException)
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow no handler.", e.Id.ToString()));
}
}
}
}

多值字典和链表范围

GameFramework的多值字典(GameFrameworkMultiDictionary)和链表范围(GameFrameworkLinkedListRange)是GameFramework的基础模块。这里的目的是为了满足同一事件多个事件处理函数的需求。是GF里面存储管理事件的形式。

先说链表范围,链表范围这个说法顾名思义,表示的就是“链表中的某个范围”。通过确定起始节点和终止节点,就可以确定一个链表范围。这里的作用是用于确定单个事件所包含哪些事件处理函数。
多值字典里面包含两个定义m_LinkedList 和 m_Dictionary:

1
2
private readonly GameFrameworkLinkedList<TValue> m_LinkedList;
private readonly Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> m_Dictionary;

通过m_LinkedList链表来存储所有的事件处理函数,m_Dictionary则是根据事件ID来存储对应事件处理函数的链表范围。这样做的好处便是,只需要通过一条链表就可以确定好一个事件有哪些事件处理函数,而不需要每一个事件都去单独创建一个链表去填充。

源码:
GameFrameworkMultiDictionary:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace GameFramework
{
/// <summary>
/// 游戏框架多值字典类。
/// </summary>
/// <typeparam name="TKey">指定多值字典的主键类型。</typeparam>
/// <typeparam name="TValue">指定多值字典的值类型。</typeparam>
public sealed class GameFrameworkMultiDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerable
{
private readonly GameFrameworkLinkedList<TValue> m_LinkedList;
private readonly Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> m_Dictionary;

/// <summary>
/// 初始化游戏框架多值字典类的新实例。
/// </summary>
public GameFrameworkMultiDictionary()
{
m_LinkedList = new GameFrameworkLinkedList<TValue>();
m_Dictionary = new Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>();
}

/// <summary>
/// 获取多值字典中实际包含的主键数量。
/// </summary>
public int Count
{
get
{
return m_Dictionary.Count;
}
}

/// <summary>
/// 获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>指定主键的范围。</returns>
public GameFrameworkLinkedListRange<TValue> this[TKey key]
{
get
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
m_Dictionary.TryGetValue(key, out range);
return range;
}
}

/// <summary>
/// 清理多值字典。
/// </summary>
public void Clear()
{
m_Dictionary.Clear();
m_LinkedList.Clear();
}

/// <summary>
/// 检查多值字典中是否包含指定主键。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <returns>多值字典中是否包含指定主键。</returns>
public bool Contains(TKey key)
{
return m_Dictionary.ContainsKey(key);
}

/// <summary>
/// 检查多值字典中是否包含指定值。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <param name="value">要检查的值。</param>
/// <returns>多值字典中是否包含指定值。</returns>
public bool Contains(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
return range.Contains(value);
}

return false;
}

/// <summary>
/// 尝试获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="range">指定主键的范围。</param>
/// <returns>是否获取成功。</returns>
public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange<TValue> range)
{
return m_Dictionary.TryGetValue(key, out range);
}

/// <summary>
/// 向指定的主键增加指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
public void Add(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
m_LinkedList.AddBefore(range.Terminal, value);
}
else
{
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
}
}

/// <summary>
/// 从指定的主键中移除指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
for (LinkedListNode<TValue> current = range.First; current != null && current != range.Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
if (current == range.First)
{
LinkedListNode<TValue> next = current.Next;
if (next == range.Terminal)
{
m_LinkedList.Remove(next);
m_Dictionary.Remove(key);
}
else
{
m_Dictionary[key] = new GameFrameworkLinkedListRange<TValue>(next, range.Terminal);
}
}

m_LinkedList.Remove(current);
return true;
}
}
}

return false;
}

/// <summary>
/// 从指定的主键中移除所有的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>是否移除成功。</returns>
public bool RemoveAll(TKey key)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
m_Dictionary.Remove(key);

LinkedListNode<TValue> current = range.First;
while (current != null)
{
LinkedListNode<TValue> next = current != range.Terminal ? current.Next : null;
m_LinkedList.Remove(current);
current = next;
}

return true;
}

return false;
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_Dictionary);
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>> IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerator
{
private Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>.Enumerator m_Enumerator;

internal Enumerator(Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> dictionary)
{
if (dictionary == null)
{
throw new GameFrameworkException("Dictionary is invalid.");
}

m_Enumerator = dictionary.GetEnumerator();
}

/// <summary>
/// 获取当前结点。
/// </summary>
public KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>> Current
{
get
{
return m_Enumerator.Current;
}
}

/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}

/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}

/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}

/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>)m_Enumerator).Reset();
}
}
}
}

GameFrameworkLinkedListRange:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace GameFramework
{
/// <summary>
/// 游戏框架链表范围。
/// </summary>
/// <typeparam name="T">指定链表范围的元素类型。</typeparam>
[StructLayout(LayoutKind.Auto)]
public struct GameFrameworkLinkedListRange<T> : IEnumerable<T>, IEnumerable
{
private readonly LinkedListNode<T> m_First;
private readonly LinkedListNode<T> m_Terminal;

/// <summary>
/// 初始化游戏框架链表范围的新实例。
/// </summary>
/// <param name="first">链表范围的开始结点。</param>
/// <param name="terminal">链表范围的终结标记结点。</param>
public GameFrameworkLinkedListRange(LinkedListNode<T> first, LinkedListNode<T> terminal)
{
if (first == null || terminal == null || first == terminal)
{
throw new GameFrameworkException("Range is invalid.");
}

m_First = first;
m_Terminal = terminal;
}

/// <summary>
/// 获取链表范围是否有效。
/// </summary>
public bool IsValid
{
get
{
return m_First != null && m_Terminal != null && m_First != m_Terminal;
}
}

/// <summary>
/// 获取链表范围的开始结点。
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_First;
}
}

/// <summary>
/// 获取链表范围的终结标记结点。
/// </summary>
public LinkedListNode<T> Terminal
{
get
{
return m_Terminal;
}
}

/// <summary>
/// 获取链表范围的结点数量。
/// </summary>
public int Count
{
get
{
if (!IsValid)
{
return 0;
}

int count = 0;
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
count++;
}

return count;
}
}

/// <summary>
/// 检查是否包含指定值。
/// </summary>
/// <param name="value">要检查的值。</param>
/// <returns>是否包含指定值。</returns>
public bool Contains(T value)
{
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
return true;
}
}

return false;
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private readonly GameFrameworkLinkedListRange<T> m_GameFrameworkLinkedListRange;
private LinkedListNode<T> m_Current;
private T m_CurrentValue;

internal Enumerator(GameFrameworkLinkedListRange<T> range)
{
if (!range.IsValid)
{
throw new GameFrameworkException("Range is invalid.");
}

m_GameFrameworkLinkedListRange = range;
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}

/// <summary>
/// 获取当前结点。
/// </summary>
public T Current
{
get
{
return m_CurrentValue;
}
}

/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_CurrentValue;
}
}

/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
}

/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange.m_Terminal)
{
return false;
}

m_CurrentValue = m_Current.Value;
m_Current = m_Current.Next;
return true;
}

/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}
}
}
}

解决抛出和取消订阅同一事件的冲突

上面也说到,在事件抛出的时候,如果收到了此事件的取消订阅,这时候就会出现冲突,这里的处理方式是通过m_CachedNodes和m_TempNodes两个事件节点缓存字典来解决。如果但看HandleEvent方法,就会发现这里的缓存其实是没有绝对的功能执行必要的,而之所以添加的目的也就是添加判断冲突存在的“标识”。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/// <summary>
/// 处理事件结点。
/// </summary>
/// <param name="sender">事件源。</param>
/// <param name="e">事件参数。</param>
private void HandleEvent(object sender, T e)
{
bool noHandlerException = false;
GameFrameworkLinkedListRange<EventHandler<T>> range = default(GameFrameworkLinkedListRange<EventHandler<T>>);
if (m_EventHandlers.TryGetValue(e.Id, out range))
{
LinkedListNode<EventHandler<T>> current = range.First;
while (current != null && current != range.Terminal)
{
m_CachedNodes[e] = current.Next != range.Terminal ? current.Next : null;
current.Value(sender, e);
current = m_CachedNodes[e];
}

m_CachedNodes.Remove(e);
}
else if (m_DefaultHandler != null)
{
m_DefaultHandler(sender, e);
}
else if ((m_EventPoolMode & EventPoolMode.AllowNoHandler) == 0)
{
noHandlerException = true;
}

ReferencePool.Release(e);

if (noHandlerException)
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow no handler.", e.Id.ToString()));
}
}

/// <summary>
/// 取消订阅事件处理函数。
/// </summary>
/// <param name="id">事件类型编号。</param>
/// <param name="handler">要取消订阅的事件处理函数。</param>
public void Unsubscribe(int id, EventHandler<T> handler)
{
if (handler == null)
{
throw new GameFrameworkException("Event handler is invalid.");
}

if (m_CachedNodes.Count > 0)
{
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in m_CachedNodes)
{
if (cachedNode.Value != null && cachedNode.Value.Value == handler)
{
m_TempNodes.Add(cachedNode.Key, cachedNode.Value.Next);
}
}

if (m_TempNodes.Count > 0)
{
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in m_TempNodes)
{
m_CachedNodes[cachedNode.Key] = cachedNode.Value;
}

m_TempNodes.Clear();
}
}

if (!m_EventHandlers.Remove(id, handler))
{
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not exists specified handler.", id.ToString()));
}
}


参考文档