装箱/拆箱
为了解释“为什么不用object传递参数?”先简单介绍一下“装箱/拆箱”,请看下面代码:
代码语言:javascript复制int a = 10;
object b = a; //装箱
a = (int)b; //拆箱
第二行,会在堆上实例化一个装箱的对象,并把a的值复制进去,b 引用的就是这个对象。 第三行,会再次进行值复制,若 b 不再引用,则需等待垃圾回收。
常见的事件管理器
我们看一些常见的事件管理器使用代码:
代码语言:javascript复制void Start()
{
//注册事件
EventManager.AddEventListener("Click", OnClick);
}
public void OnClick(object data)
{
Debug.Log("clickBlock: " data);
}
//派发事件
EventManager.dispatchEvent("Click", 123);
如上所述,若传递的是引用类型则不会有影响。但如果传递的是值类型,就会产生上述的性能消耗。 泛型优化 我们可以通过泛型去设置参数的类型,从而不需要通过 object 类型传递参数:
public void Dispatch
代码语言:javascript复制void Start()
{
//注册事件
EventDispatcher.global.AddListener<int>("Click", OnClick);
}
public void OnClick(int data)
{
Debug.Log("clickBlock: " data);
Debug.Log(gameObject.name);
}
void OnDestroy()
{
EventDispatcher.global.RemoveListener<int>("Click",OnClick);
}
//派发事件
EventDispatcher.global.Dispatch<int>("Click", 123);
这里要注意的是一定要GameObject销毁时调用注销委托,不然可能出现如下错误
完整代码
如下:
代码语言:javascript复制using System;
using System.Collections.Generic;
public class EventDispatcher
{
public static EventDispatcher global
{
get;
private set;
}
static EventDispatcher()
{
global = new EventDispatcher();
}
private Dictionary<string, Delegate> _listeners = new Dictionary<string, Delegate>();
public void AddListener<T1, T2, T3, T4>(string evt, Action<T1, T2, T3, T4> callback)
{
AddListener(evt, (Delegate)callback);
}
public void AddListener<T1, T2, T3>(string evt, Action<T1, T2, T3> callback)
{
AddListener(evt, (Delegate)callback);
}
public void AddListener<T1, T2>(string evt, Action<T1, T2> callback)
{
AddListener(evt, (Delegate)callback);
}
public void AddListener<T>(string evt, Action<T> callback)
{
AddListener(evt, (Delegate)callback);
}
public void AddListener(string evt, Action callback)
{
AddListener(evt, (Delegate)callback);
}
public void AddListener(string evt, Delegate callback)
{
Delegate listener;
if (_listeners.TryGetValue(evt, out listener))
{
_listeners[evt] = Delegate.Combine(listener, callback);
}
else
{
_listeners[evt] = callback;
}
}
public void RemoveListener<T1, T2, T3, T4>(string evt, Action<T1, T2, T3, T4> callback)
{
RemoveListener(evt, (Delegate)callback);
}
public void RemoveListener<T1, T2, T3>(string evt, Action<T1, T2, T3> callback)
{
RemoveListener(evt, (Delegate)callback);
}
public void RemoveListener<T1, T2>(string evt, Action<T1, T2> callback)
{
RemoveListener(evt, (Delegate)callback);
}
public void RemoveListener<T>(string evt, Action<T> callback)
{
RemoveListener(evt, (Delegate)callback);
}
public void RemoveListener(string evt, Action callback)
{
RemoveListener(evt, (Delegate)callback);
}
private void RemoveListener(string evt, Delegate callback)
{
Delegate listener;
if (_listeners.TryGetValue(evt, out listener))
{
listener = Delegate.Remove(listener, callback);
if (listener == null)
{
_listeners.Remove(evt);
}
else
{
_listeners[evt] = listener;
}
}
}
public void Dispatch<T1, T2, T3, T4>(string evt, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
Delegate[] methods = GetMethods(evt);
if (methods != null)
{
foreach (Delegate m in methods)
{
try
{
if (m.Target != null)
((Action<T1, T2, T3, T4>)m)(arg1, arg2, arg3, arg4);
}
catch (Exception e) { LogError(e); }
}
}
}
public void Dispatch<T1, T2, T3>(string evt, T1 arg1, T2 arg2, T3 arg3)
{
Delegate[] methods = GetMethods(evt);
if (methods != null)
{
foreach (Delegate m in methods)
{
try
{
if (m.Target != null)
((Action<T1, T2, T3>)m)(arg1, arg2, arg3);
}
catch (Exception e) { LogError(e); }
}
}
}
public void Dispatch<T1, T2>(string evt, T1 arg1, T2 arg2)
{
Delegate[] methods = GetMethods(evt);
if (methods != null)
{
foreach (Delegate m in methods)
{
try
{
if (m.Target != null)
((Action<T1, T2>)m)(arg1, arg2);
}
catch (Exception e) { LogError(e); }
}
}
}
public void Dispatch<T>(string evt, T arg)
{
Delegate[] methods = GetMethods(evt);
if (methods != null)
{
foreach (Delegate m in methods)
{
try
{
if (m.Target != null)
{
((Action<T>)m)(arg);
}
}
catch (Exception e) { LogError(e); }
}
}
}
public void Dispatch(string evt)
{
Delegate[] methods = GetMethods(evt);
if (methods != null)
{
foreach (Delegate m in methods)
{
try
{
if (m.Target != null)
((Action)m)();
}
catch (Exception e) { LogError(e); }
}
}
}
private Delegate[] GetMethods(string evt)
{
Delegate listener;
if (_listeners.TryGetValue(evt, out listener))
{
return listener.GetInvocationList();
}
return null;
}
private static void LogError(Exception e)
{
UnityEngine.Debug.LogError(e);
}
}
代码分析
订阅消息时
代码语言:javascript复制_listeners[evt] = Delegate.Combine(listener, callback);
Delegate.Combine将指定的多路广播(可组合)委托的调用列表连接起来,相当于事件的 = 方法
发送消息时
代码语言:javascript复制listener.GetInvocationList()
GetInvocationList得到链式委托
取消订阅时
代码语言:javascript复制listener = Delegate.Remove(listener, callback);
Delegate.Remove相当于 -= 方法