C#事件使用+= -=使用起来是很方便的,但是却不能整体清空所有事件。比如一个常见的操作,打开界面注册监听事件,关闭界面需要把所有的事件清空了,这要在写一堆-=操作,如果漏清空的话肯定会造成隐患,如果在lua里这个很容易,但是C#却不行。所以我想了个办法,对Action和Func进行一次包装,就可以解决这个问题了。
这里我只封装了两个参数,大家可以继续拓展新的参数,我在项目里一共拓展了5个参数,完全够用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
using System; using System.Collections.Generic; public class ActionManager { Dictionary<object, object> m_Actions = new Dictionary<object, object>(); public NewAction RegAction(NewAction newAction , Action action) { newAction += action; m_Actions[newAction] = action; return newAction; } public NewAction<T1> RegAction<T1>(NewAction<T1> newAction, Action<T1> action) { newAction += action; m_Actions[newAction] = action; return newAction; } public NewFunc<T1> RegAction<T1>(NewFunc<T1> newAction, Func<T1> action) { newAction += action; m_Actions[newAction] = action; return newAction; } public NewFunc<T1,T2> RegAction<T1, T2>(NewFunc<T1, T2> newAction, Func<T1, T2> action) { newAction += action; m_Actions[newAction] = action; return newAction; } public void Clear() { foreach (var act in m_Actions) { ((IAction)act.Key).Dispose(act.Value); } } } public interface IAction { void Dispose(object obj); } public class NewAction : IAction { Action action; public void Dispose(object obj) { if(obj is Action act) action -= act; } public void Invoke() { action?.Invoke(); } public static NewAction operator +(NewAction a, Action b) { a.action -= b; a.action += b; return a; } public static NewAction operator -(NewAction a, Action b) { a.action -= b; return a; } } public class NewAction<T1> : IAction { Action<T1> action; public void Dispose(object obj) { if (obj is Action<T1> act) action -= act; } public void Invoke(T1 t1) { action?.Invoke(t1); } public static NewAction<T1> operator +(NewAction<T1> a, Action<T1> b) { a.action -= b; a.action += b; return a; } public static NewAction<T1> operator -(NewAction<T1> a, Action<T1> b) { a.action -= b; return a; } } public class NewFunc<T1> : IAction { Func<T1> func; public void Dispose(object obj) { if (obj is Func<T1> act) func -= act; } public T1 Invoke() { return func != null ? func.Invoke() : default(T1); } public static NewFunc<T1> operator +(NewFunc<T1> a, Func<T1> b) { a.func -= b; a.func += b; return a; } public static NewFunc<T1> operator -(NewFunc<T1> a, Func<T1> b) { a.func -= b; return a; } } public class NewFunc<T1, T2> : IAction { Func<T1, T2> func; public void Dispose(object obj) { if (obj is Func<T1, T2> act) func -= act; } public T2 Invoke(T1 t1) { return func != null ? func.Invoke(t1) : default(T2); } public static NewFunc<T1, T2> operator +(NewFunc<T1, T2> a, Func<T1, T2> b) { a.func -= b; a.func += b; return a; } public static NewFunc<T1, T2> operator -(NewFunc<T1, T2> a, Func<T1, T2> b) { a.func -= b; return a; } } |
使用方法如下,注意我们自己封装的事件必须要new。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using UnityEngine; public class Main : MonoBehaviour { NewAction<string> MyAction = new NewAction<string>();//事件需要new NewFunc<string,int> MyFunc = new NewFunc<string,int>();//事件需要new ActionManager m_ActionManager = new ActionManager(); public void MyFunction(string str) { Debug.Log(" MyFunction " + str); } public int MyFunction1(string str) { Debug.Log(" MyFunction1 " + str); return 1; } private void OnGUI() { if (GUILayout.Button("<size=50>注册事件</size>")) { m_ActionManager.RegAction(MyAction, MyFunction); m_ActionManager.RegAction(MyFunc, MyFunction1); } if (GUILayout.Button("<size=50>发事件</size>")) { MyAction.Invoke("参数1"); MyFunc.Invoke("参数2"); } if (GUILayout.Button("<size=50>清空</size>")) { m_ActionManager.Clear(); } } } |
事件管理器可以放在UI或者模块的基类中,这样子类在写的时候可以直接this.RegAction注册事件,关闭界面或者卸载模块的时候由父类调用Clear方法,这样业务逻辑就不需要在写-=这样的代码了。
欢迎大家互相讨论。
- 本文固定链接: https://www.xuanyusong.com/archives/4742
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!
直接用unity内置的UnityEvent如何?直接就有removeall的方法
假如有一个独立的模块专门管理事件的监听,那是不是不存在这个问题了
得看怎么实现了, 因为注册的地方的类对象已经没有了,但是它的方法注册还存在,要把这个方法移除才行。
action=null,是不是就等于清空了?
同问~似乎没有奇怪的问题
支持一下
虽然感觉有些鸡肋,但还是赞一个