在使用c#中的事件时,经同事推荐看到了这个框架,它是c#消息传递的高级版本,代码不多,拜读之后对代码结构进行了重构,感觉更清晰点
/*
* Advanced C# messenger by Ilya Suzdalnitski. V1.0
*
* Based on Rod Hyde's "CSharpMessenger" and Magnus Wolffelt's "CSharpMessenger Extended".
*
* Features:
* Prevents a MissingReferenceException because of a reference to a destroyed message handler.
* Option to log all messages
* Extensive error detection, preventing silent bugs
*
* Usage examples:
1. Messenger.AddListener<GameObject>("prop collected", PropCollected);
Messenger.Broadcast<GameObject>("prop collected", prop);
2. Messenger.AddListener<float>("speed changed", SpeedChanged);
Messenger.Broadcast<float>("speed changed", 0.5f);
*
* Messenger cleans up its evenTable automatically upon loading of a new level.
*
* Don't forget that the messages that should survive the cleanup, should be marked with Messenger.MarkAsPermanent(string)
*
*/
//宏定不许删除,为以后测试方便
//#define LOG_ALL_MESSAGES
//#define LOG_ADD_LISTENER
//#define LOG_BROADCAST_MESSAGE
#define REQUIRE_LISTENER
using System;
using System.Collections.Generic;
using UnityEngine;
namespace GG
{
public class Messenger
{
public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
//Message handlers that should never be removed, regardless of calling Cleanup
public static List<string> permanentMessages = new List<string>();
#region Helper methods
//Marks a certain message as permanent.
public static void MarkAsPermanent(string eventType)
{
#if LOG_ALL_MESSAGES
Debug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\"");
#endif
permanentMessages.Add(eventType);
}
public static void Cleanup()
{
#if LOG_ALL_MESSAGES
Debug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed.");
#endif
List<string> messagesToRemove = new List<string>();
foreach (KeyValuePair<string, Delegate> pair in eventTable)
{
bool wasFound = false;
foreach (string message in permanentMessages)
{
if (pair.Key == message)
{
wasFound = true;
break;
}
}
if (!wasFound)
messagesToRemove.Add(pair.Key);
}
foreach (string message in messagesToRemove)
{
eventTable.Remove(message);
}
}
public static void PrintEventTable()
{
Debug.Log("\t\t\t=== MESSENGER PrintEventTable ===");
foreach (KeyValuePair<string, Delegate> pair in eventTable)
{
Debug.Log("\t\t\t" + pair.Key + "\t\t" + pair.Value);
}
Debug.Log("\n");
}
#endregion
#region Message logging and exception throwing
public static void OnListenerAdding(string eventType, Delegate listenerBeingAdded)
{
#if LOG_ALL_MESSAGES || LOG_ADD_LISTENER
Debug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}");
#endif
if (!eventTable.ContainsKey(eventType))
{
eventTable.Add(eventType, null);
}
Delegate d = eventTable[eventType];
if (d != null && d.GetType() != listenerBeingAdded.GetType())
{
throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name));
}
}
public static void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved)
{
#if LOG_ALL_MESSAGES
Debug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}");
#endif
if (eventTable.ContainsKey(eventType))
{
Delegate d = eventTable[eventType];
if (d == null)
{
throw new ListenerException(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", eventType));
}
else if (d.GetType() != listenerBeingRemoved.GetType())
{
throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name));
}
}
else
{
throw new ListenerException(string.Format("Attempting to remove listener for type \"{0}\" but Messenger doesn't know about this event type.", eventType));
}
}
public static void OnListenerRemoved(string eventType)
{
if (eventTable[eventType] == null)
{
eventTable.Remove(eventType);
}
}
public static void OnBroadcasting(string eventType)
{
#if REQUIRE_LISTENER
if (!eventTable.ContainsKey(eventType))
{
throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", eventType));
}
#endif
}
public static BroadcastException CreateBroadcastSignatureException(string eventType)
{
return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType));
}
public class BroadcastException : Exception
{
public BroadcastException(string msg)
: base(msg)
{
}
}
public class ListenerException : Exception
{
public ListenerException(string msg)
: base(msg)
{
}
}
#endregion
}
#region No parameters
public class MessengerMgr : Messenger
{
public static void AddListener(string eventType, Callback handler)
{
OnListenerAdding(eventType, handler);
var temp = (Callback)eventTable[eventType];
temp += handler;
eventTable[eventType] = (Callback)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback handler)
{
OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] - handler;
OnListenerRemoved(eventType);
}
public static void Broadcast(string eventType)
{
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
OnBroadcasting(eventType);
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback callback = d as Callback;
if (callback != null)
{
callback();
}
else
{
throw CreateBroadcastSignatureException(eventType);
}
}
}
}
#endregion
#region Single parameters
public class MessengerMgr<T> : Messenger
{
public static void AddListener(string eventType, Callback<T> handler)
{
OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback<T> handler)
{
OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
OnListenerRemoved(eventType);
}
public static void Broadcast(string eventType, T arg1)
{
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
OnBroadcasting(eventType);
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback<T> callback = d as Callback<T>;
if (callback != null)
{
callback(arg1);
}
else
{
throw CreateBroadcastSignatureException(eventType);
}
}
}
}
#endregion
#region Two parameters
public class MessengerMgr<T, U> : Messenger
{
public static void AddListener(string eventType, Callback<T, U> handler)
{
OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback<T, U> handler)
{
OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback<T, U>)eventTable[eventType] - handler;
OnListenerRemoved(eventType);
}
public static void Broadcast(string eventType, T arg1, U arg2)
{
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
OnBroadcasting(eventType);
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback<T, U> callback = d as Callback<T, U>;
if (callback != null)
{
callback(arg1, arg2);
}
else
{
throw CreateBroadcastSignatureException(eventType);
}
}
}
}
#endregion
#region Three parameters
public class MessengerMgr<T, U, V> : Messenger
{
public static void AddListener(string eventType, Callback<T, U, V> handler)
{
OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] + handler;
}
public static void RemoveListener(string eventType, Callback<T, U, V> handler)
{
OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] - handler;
OnListenerRemoved(eventType);
}
public static void Broadcast(string eventType, T arg1, U arg2, V arg3)
{
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
OnBroadcasting(eventType);
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback<T, U, V> callback = d as Callback<T, U, V>;
if (callback != null)
{
callback(arg1, arg2, arg3);
}
else
{
throw CreateBroadcastSignatureException(eventType);
}
}
}
}
#endregion
}
委托类型定义:
/**
* 命名空间: namespace GG
* 功 能: 消息回调函数类型
* 类 名: 无
* 创建人:zxh
* 创建时间:2018/11/23 13:42:52
* Copyright (c) 2018 gg Corporation. All rights reserved.
*/
namespace GG
{
public delegate void Callback();
public delegate void Callback<T>(T arg1);
public delegate void Callback<T, U>(T arg1, U arg2);
public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
}
包装层:
纯属个人编码习惯,包一层尽量做到使用和实现分离
/**
* 命名空间: namespace GG
* 功 能: 消息包装层
* 类 名: EventManager
* 创建人:zxh
* 创建时间:2018/11/23 13:42:52
* Copyright (c) 2018 gg Corporation. All rights reserved.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XLua;
namespace GG
{
[LuaCallCSharp]
public class EventManager
{
public static void AddEventListener(string eventName, Callback callback)
{
MessengerMgr.AddListener(eventName, callback);
}
public static void AddEventListener<T>(string eventName, Callback<T> callback)
{
MessengerMgr<T>.AddListener(eventName, callback);
}
public static void AddEventListener<T, U>(string eventName, Callback<T, U> callback)
{
MessengerMgr<T, U>.AddListener(eventName, callback);
}
public static void AddEventListener<T, U, V>(string eventName, Callback<T, U, V> callback)
{
MessengerMgr<T, U, V>.AddListener(eventName, callback);
}
public static void RemoVeEventListener(string eventName, Callback callback)
{
MessengerMgr.RemoveListener(eventName, callback);
}
public static void RemoVeEventListener<T>(string eventName, Callback<T> callback)
{
MessengerMgr<T>.RemoveListener(eventName, callback);
}
public static void RemoVeEventListener<T, U>(string eventName, Callback<T, U> callback)
{
MessengerMgr<T, U>.RemoveListener(eventName, callback);
}
public static void RemoVeEventListener<T, U, V>(string eventName, Callback<T, U, V> callback)
{
MessengerMgr<T, U, V>.RemoveListener(eventName, callback);
}
public static void DispatchEvent(string eventName)
{
MessengerMgr.Broadcast(eventName);
}
public static void DispatchEvent<T>(string eventName, T arg1)
{
MessengerMgr<T>.Broadcast(eventName, arg1);
}
public static void DispatchEvent<T, U>(string eventName, T arg1 , U arg2)
{
MessengerMgr<T, U>.Broadcast(eventName, arg1, arg2);
}
public static void DispatchEvent<T, U, V>(string eventName, T arg1, U arg2, V arg3)
{
MessengerMgr<T, U, V>.Broadcast(eventName, arg1, arg2, arg3);
}
}
}
源码共有两个文件,加上我包装的一层有三个文件,代码结构很清晰,使用也很简单,就是一个观察者模式的实现,相信对c#有了解的开发人员都能看懂,