学习来源:https://liangxiegame.com/zhuanlan/content/detail/61edfc3b-05df-45b2-9b71-2f2d42835b6a
把凉鞋的代码整理了一下,事件收发写到了一起,代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript1 : MonoBehaviour, IMsgReceiver, IMsgSender
{
void Start()
{
//注册消息,其中string是消息名,ReceiveMsg是委托回调
this.RegisterLogicMsg("Receiver Show Sth", ReceiveMsg);
this.SendLogicMsg("Receiver Show Sth", "你好", "世界");
}
private void ReceiveMsg(object[] args)
{
foreach (var arg in args)
{
Debug.Log(arg);
}
}
}
public interface IMsgReceiver
{
}
public interface IMsgSender
{
}
public static class MsgDispatcher
{
/// <summary>
/// 消息捕捉器
/// </summary>
private class LogicMsgHandler
{
public readonly IMsgReceiver Receiver;
public readonly Action<object[]> Callback;
public LogicMsgHandler(IMsgReceiver receiver, Action<object[]> callback)
{
Receiver = receiver;
Callback = callback;
}
}
/// <summary>
/// 每个消息名字维护一组消息捕捉器。
/// </summary>
static readonly Dictionary<string, List<LogicMsgHandler>> mMsgHandlerDict =
new Dictionary<string, List<LogicMsgHandler>>();
/// <summary>
/// 注册消息,
/// 注意第一个参数,使用了C# this的扩展,
/// 所以只有实现IMsgReceiver的对象才能调用此方法
/// </summary>
public static void RegisterLogicMsg(this IMsgReceiver self, string msgName, Action<object[]> callback)
{
// 略过
if (string.IsNullOrEmpty(msgName))
{
Debug.LogWarning("RegisterMsg:" + msgName + " is Null or Empty");
return;
}
// 略过
if (null == callback)
{
Debug.LogWarning("RegisterMsg:" + msgName + " callback is Null");
return;
}
// 略过
if (!mMsgHandlerDict.ContainsKey(msgName))
{
mMsgHandlerDict[msgName] = new List<LogicMsgHandler>();
}
// 看下这里
var handlers = mMsgHandlerDict[msgName];
// 略过
// 防止重复注册
foreach (var handler in handlers)
{
if (handler.Receiver == self && handler.Callback == callback)
{
Debug.LogWarning("RegisterMsg:" + msgName + " ayready Register");
return;
}
}
// 再看下这里
handlers.Add(new LogicMsgHandler(self, callback));
}
/// <summary>
/// 发送消息
/// 注意第一个参数
/// </summary>
public static void SendLogicMsg(this IMsgSender sender, string msgName, params object[] paramList)
{
// 略过,不用看
if (string.IsNullOrEmpty(msgName))
{
Debug.LogWarning("SendMsg is Null or Empty");
return;
}
// 略过,不用看
if (!mMsgHandlerDict.ContainsKey(msgName))
{
Debug.LogWarning("SendMsg is UnRegister");
return;
}
// 开始看!!!!
var handlers = mMsgHandlerDict[msgName];
var handlerCount = handlers.Count;
// 之所以是从后向前遍历,是因为 从前向后遍历删除后索引值会不断变化
// 参考文章,http://www.2cto.com/kf/201312/266723.html
for (var index = handlerCount - 1; index >= 0; index--)
{
var handler = handlers[index];
if (handler.Receiver != null)
{
Debug.LogWarning("SendLogicMsg:" + msgName + " Succeed");
handler.Callback(paramList);
}
else
{
handlers.Remove(handler);
}
}
}
}
总结:先定义了两个空接口IMsgReceiver和IMsgSender。然后定义了LogicMsgHandler消息捕捉器,包含一个接受者IMsgReceiver和一个回调,mMsgHandlerDict作为全局的所有事件的Dictionary。通过RegisterLogicMsg注册事件,通过SendLogicMsg发送事件,遍历mMsgHandlerDict中对应事件绑定的全部回调。
实际上是接口+接口扩展方法的用法实现了该消息机制。