消息机制的优化----------无需进行装箱/拆箱的 版本
http://www.manew.com/thread-111056-1-1.html
装箱/拆箱
为了解释“为什么不用object传递参数?”先简单介绍一下“装箱/拆箱”,请看下面代码:
[C#] 纯文本查看 复制代码
int a = 10;
object b = a; //装箱
a = (int)b; //拆箱
第二行,会在堆上实例化一个装箱的对象,并把a的值复制进去,b 引用的就是这个对象。
第三行,会再次进行值复制,若 b 不再引用,则需等待垃圾回收。
常见的事件管理器
我们看一些常见的事件管理器使用代码:
[C#] 纯文本查看 复制代码
void Start()
{
//注册事件
EventManager.AddEventListener("Click", OnClick);
}
public void OnClick(object data)
{
Debug.Log("clickBlock: " + data);
}
//派发事件
EventManager.dispatchEvent("Click", 123);
如上所述,若传递的是引用类型则不会有影响。但如果传递的是值类型,就会产生上述的性能消耗。
泛型优化
我们可以通过泛型去设置参数的类型,从而不需要通过 object 类型传递参数:
[C#] 纯文本查看 复制代码
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
{
((Action<T1, T2, T3, T4>)m)(arg1, arg2, arg3, arg4);
}
catch (Exception e) { LogError(e); }
}
}
}
将上面的代码,改为用泛型事件管理器:
[C#] 纯文本查看 复制代码
void Start()
{
//注册事件
EventDispatcher.global.AddListener<int>("Click", OnClick);
}
public void OnClick(int data)
{
Debug.Log("clickBlock: " + data);
}
//派发事件
EventDispatcher.global.Dispatch<int>("Click", 123);
另:该事件管理器还支持【继承】与【实例化】,因此可以在非脚本对象和派生自MonoBehaviour的实例中使用。
完整代码:
本帖隐藏的内容
[C#] 纯文本查看 复制代码
/*
* Author: Rick
* Create: 2017/11/21 16:47:25
* Email: rickjiangshu@gmail.com
* Follow: https://github.com/RickJiangShu
*/
using System;
using System.Collections.Generic;
/// <summary>
/// 事件派发器
/// 1. 优化装箱/拆箱
/// 2. 不使用闭包
/// </summary>
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
{
((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
{
((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
{
((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
{
((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
{
((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);
}
}