前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >unity3d无需进行装箱/拆箱的【事件管理器】

unity3d无需进行装箱/拆箱的【事件管理器】

作者头像
立羽
发布2023-08-24 14:10:24
2110
发布2023-08-24 14:10:24
举报
文章被收录于专栏:Unity3d程序开发Unity3d程序开发

装箱/拆箱

为了解释“为什么不用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相当于 -= 方法

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装箱/拆箱
  • 常见的事件管理器
  • 完整代码
  • 代码分析
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档