注:转载请标明原文地址:https://segmentfault.com/a/11...
在Unity中 用C#实现自定义的事件系统参考自《Advanced C# Messenger》 实现一个高效的,独立的,可复用的事件系统。这种方式实现的事件,GC会很低,值类型0GC。
注:《Advanced C# Messenger》中使用泛型Delegate实现的事件系统,发送事件参数没有类型转换,实现0GC的效果,但是IL2CPP后,所有泛型都生成了对应的静态类型代码,用的越多生成的代码体积越庞大,运行时占用的内存也越多,相当于用空间换了时间。但当类型过于丰富时,展开的代码太过庞大,性价比急剧降低。所以个人弃用这种实现方式,转为传统用法,Advanced只做参考学习用,下面为传统实现。
用法:
// 定义事件类型
// 用枚举类型定义, 强制约定,避免出现因为string或int值打错产生的错误
public enum EventType {
ShowMainCamera,
HideMainCamera
}
// 添加事件监听器
EventUtil.AddListener(EventType, OnCallback)
// 移除事件监听器
EventUtil.RemoveListener(EventType, OnCallback)
// 发送事件(无参数)
EventUtil.SendMessage(EventType)
// 发送事件(1个参数)
EventUtil.SendMessage(EventType, "arg1")
// 发送事件(多个参数)
EventUtil.SendMessage(EventType, new string[]{"arg1", "arg2", "arg3"})
// 事件回调(无参数)
private void OnCallback(object arg) {
print(arg); // null
}
// 事件回调(1个参数)
private void OnCallback1(object arg) {
print(arg); // "arg1"
}
// 事件回调(多个参数)
private void OnCallbackN(object arg) {
string[] args = (string[])arg;
print(args); // System.String[]
}
测试代码
EventDemo.cs
using UnityEngine;
/// <summary>
/// 事件测试Demo
/// ZhangYu 2019-12-25
/// </summary>
public class EventDemo : MonoBehaviour {
// 定义事件类型
public enum EventType {
Arg0,
Arg1,
ArgN
}
private void Start() {
AddListeners();
SendMessages();
}
private void OnDestroy() {
RemoveListeners();
EventUtil.Clear();
}
// 添加事件监听器
private void AddListeners() {
EventUtil.AddListener(EventType.Arg0, OnCall0);
EventUtil.AddListener(EventType.Arg1, OnCall1);
EventUtil.AddListener(EventType.ArgN, OnCallN);
}
// 移除事件监听器
private void RemoveListeners() {
EventUtil.RemoveListener(EventType.Arg0, OnCall0);
EventUtil.RemoveListener(EventType.Arg1, OnCall1);
EventUtil.RemoveListener(EventType.ArgN, OnCallN);
}
// 发送事件
public void SendMessages() {
EventUtil.SendMessage(EventType.Arg0);
EventUtil.SendMessage(EventType.Arg1, "arg1");
EventUtil.SendMessage(EventType.ArgN, new string[] { "arg1", "arg2", "arg3" });
}
private void OnCall0(object arg) {
print("无参数:" + arg);
}
private void OnCall1(object arg) {
print("1个参数:" + arg);
}
private void OnCallN(object arg) {
string[] args = (string[])arg;
print("多个参数:" + args);
}
}
实现效果:
事件工具
事件工具
EventUtil.cs
对EventSender做了一个简单封装,静态工具类,方便使用。
using System;
/// <summary>
/// 事件工具
/// <para>ZhangYu 2019-12-25</para>
/// </summary>
public static class EventUtil {
/// <summary> 事件发送器 </summary>
private static EventSender<Enum, object> sender = new EventSender<Enum, object>();
/// <summary> 添加事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public static void AddListener(Enum eventType, Action<object> eventHandler) {
sender.AddListener(eventType, eventHandler);
}
/// <summary> 移除事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public static void RemoveListener(Enum eventType, Action<object> eventHandler) {
sender.RemoveListener(eventType, eventHandler);
}
/// <summary> 是否已经拥有该类型的事件监听器 </summary>
/// <param name="eventType">事件类型</param>
public static bool HasListener(Enum eventType) {
return sender.HasListener(eventType);
}
/// <summary> 发送事件 </summary>
/// <param name="eventType">事件类型</param>
public static void SendMessage(Enum eventType) {
sender.SendMessage(eventType, null);
}
/// <summary> 发送事件 </summary>
/// <param name="eventType">事件类型</param>
public static void SendMessage(Enum eventType, object eventArg) {
sender.SendMessage(eventType, eventArg);
}
/// <summary> 清理所有事件监听器 </summary>
public static void Clear() {
sender.Clear();
}
}
事件发送器
EventSender.cs
核心类,功能都在这里实现的
using System;
using System.Collections.Generic;
/// <summary>
/// 事件发送器
/// <para>ZhangYu 2019-12-25</para>
/// <para>Blog:https://segmentfault.com/a/1190000018391937</para>
/// </summary>
public class EventSender<TKey, TValue> {
/// <summary> 事件表 </summary>
private Dictionary<TKey, Action<TValue>> dict = new Dictionary<TKey, Action<TValue>>();
/// <summary> 添加事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public void AddListener(TKey eventType, Action<TValue> eventHandler) {
Action<TValue> callbacks;
if (dict.TryGetValue(eventType, out callbacks)) {
dict[eventType] = callbacks + eventHandler;
} else {
dict.Add(eventType, eventHandler);
}
}
/// <summary> 移除事件监听器 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventHandler">事件处理器</param>
public void RemoveListener(TKey eventType, Action<TValue> eventHandler) {
Action<TValue> callbacks;
if (dict.TryGetValue(eventType, out callbacks)) {
callbacks = (Action<TValue>)Delegate.RemoveAll(callbacks, eventHandler);
if (callbacks == null) {
dict.Remove(eventType);
} else {
dict[eventType] = callbacks;
}
}
}
/// <summary> 是否已经拥有该类型的事件监听器 </summary>
/// <param name="eventType">事件名称</param>
public bool HasListener(TKey eventType) {
return dict.ContainsKey(eventType);
}
/// <summary> 发送事件 </summary>
/// <param name="eventType">事件类型</param>
/// <param name="eventArg">事件参数</param>
public void SendMessage(TKey eventType, TValue eventArg) {
Action<TValue> callbacks;
if (dict.TryGetValue(eventType, out callbacks)) {
callbacks.Invoke(eventArg);
}
}
/// <summary> 清理所有事件监听器 </summary>
public void Clear() {
dict.Clear();
}
}
核心类是EventSender,用来管理事件,可以复用,这样可以做事件隔离,各系统用不同的EventSender,互不影响。EventUtil是对EventSender的封装,封装成静态工具类,方便使用。相同的思路,可以封装成UIEventUtil、InputEventUtil、SocketEventUtil等等...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。