消息机制的优化----------无需进行装箱/拆箱的 版本

Posted 三页菌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了消息机制的优化----------无需进行装箱/拆箱的 版本相关的知识,希望对你有一定的参考价值。

消息机制的优化----------无需进行装箱/拆箱的  版本

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);
    }
}

以上是关于消息机制的优化----------无需进行装箱/拆箱的 版本的主要内容,如果未能解决你的问题,请参考以下文章

c# 泛型为啥能解决装箱拆箱问题

自动装箱拆箱

装箱拆箱

装箱与拆箱

Java包装类 — 自动装箱自动拆箱

装箱拆箱