1. 程式人生 > >消息機制的優化----------無需進行裝箱/拆箱的 版本

消息機制的優化----------無需進行裝箱/拆箱的 版本

我們 bug try clas email 引用類型 為什麽 cli small

消息機制的優化----------無需進行裝箱/拆箱的 版本

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: [email protected]
* 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);
}
}

消息機制的優化----------無需進行裝箱/拆箱的 版本