用法
編寫一個監聽事件
void OnSpeedChanged(float speed)
{
this.speed = speed;
}
註冊一個監聽事件
void OnEnable()
{
Messenger<float>.AddListener("speed changed", OnSpeedChanged);
}
取消註冊(刪除)一個監聽事件
void OnDisable()
{
Messenger<float>.RemoveListener("speed changed", OnSpeedChanged);
}
註冊回調返回
void OnDisable()
{
Messenger.AddListener<int>("getScore", GetScore);
}
int GetScore()
{
return 0;
}
void OnDisable()
{
Messenger.Broadcast<int>("getScore", OnGetScore);
}
void OnGetScore(int i)
{
Debug.Log(string.Format("Score is {0}...", i));
}
廣播一個事件
if (speed != lastSpeed)
{
Messenger<float>.Broadcast("speed changed", speed);
}
代碼
Messenger.cs
using System;
using System.Collections.Generic;
using System.Linq;
public enum MessengerMode {
DONT_REQUIRE_LISTENER,
REQUIRE_LISTENER,
}
static internal class MessengerInternal {
readonly public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public readonly MessengerMode DEFAULT_MODE = MessengerMode.REQUIRE_LISTENER;
static public void AddListener(string eventType, Delegate callback) {
MessengerInternal.OnListenerAdding(eventType, callback);
eventTable[eventType] = Delegate.Combine(eventTable[eventType], callback);
}
static public void RemoveListener(string eventType, Delegate handler) {
MessengerInternal.OnListenerRemoving(eventType, handler);
eventTable[eventType] = Delegate.Remove(eventTable[eventType], handler);
MessengerInternal.OnListenerRemoved(eventType);
}
static public T[] GetInvocationList<T>(string eventType) {
Delegate d;
if(eventTable.TryGetValue(eventType, out d)) {
try {
return d.GetInvocationList().Cast<T>().ToArray();
} catch {
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
return null;
}
static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded) {
if (!eventTable.ContainsKey(eventType)) {
eventTable.Add(eventType, null);
}
var 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));
}
}
static public void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved) {
if (eventTable.ContainsKey(eventType)) {
var 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));
}
}
static public void OnListenerRemoved(string eventType) {
if (eventTable[eventType] == null) {
eventTable.Remove(eventType);
}
}
static public void OnBroadcasting(string eventType, MessengerMode mode) {
if (mode == MessengerMode.REQUIRE_LISTENER && !eventTable.ContainsKey(eventType)) {
throw new MessengerInternal.BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType));
}
}
static public 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) {
}
}
}
static public class Messenger {
static public void AddListener(string eventType, Action handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void AddListener<TReturn>(string eventType, Func<TReturn> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void RemoveListener(string eventType, Action handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void RemoveListener<TReturn>(string eventType, Func<TReturn> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void Broadcast(string eventType) {
Broadcast(eventType, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast<TReturn>(string eventType, Action<TReturn> returnCall) {
Broadcast(eventType, returnCall, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Action>(eventType);
foreach(var callback in invocationList)
callback.Invoke();
}
static public void Broadcast<TReturn>(string eventType, Action<TReturn> returnCall, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Func<TReturn>>(eventType);
foreach(var result in invocationList.Select(del => del.Invoke()).Cast<TReturn>()) {
returnCall.Invoke(result);
}
}
}
static public class Messenger<T> {
static public void AddListener(string eventType, Action<T> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void AddListener<TReturn>(string eventType, Func<T, TReturn> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void RemoveListener(string eventType, Action<T> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void RemoveListener<TReturn>(string eventType, Func<T, TReturn> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void Broadcast(string eventType, T arg1) {
Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast<TReturn>(string eventType, T arg1, Action<TReturn> returnCall) {
Broadcast(eventType, arg1, returnCall, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, T arg1, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Action<T>>(eventType);
foreach(var callback in invocationList)
callback.Invoke(arg1);
}
static public void Broadcast<TReturn>(string eventType, T arg1, Action<TReturn> returnCall, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Func<T, TReturn>>(eventType);
foreach(var result in invocationList.Select(del => del.Invoke(arg1)).Cast<TReturn>()) {
returnCall.Invoke(result);
}
}
}
static public class Messenger<T, U> {
static public void AddListener(string eventType, Action<T, U> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void AddListener<TReturn>(string eventType, Func<T, U, TReturn> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void RemoveListener(string eventType, Action<T, U> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void RemoveListener<TReturn>(string eventType, Func<T, U, TReturn> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void Broadcast(string eventType, T arg1, U arg2) {
Broadcast(eventType, arg1, arg2, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, Action<TReturn> returnCall) {
Broadcast(eventType, arg1, arg2, returnCall, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, T arg1, U arg2, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Action<T, U>>(eventType);
foreach(var callback in invocationList)
callback.Invoke(arg1, arg2);
}
static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, Action<TReturn> returnCall, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Func<T, U, TReturn>>(eventType);
foreach(var result in invocationList.Select(del => del.Invoke(arg1, arg2)).Cast<TReturn>()) {
returnCall.Invoke(result);
}
}
}
static public class Messenger<T, U, V> {
static public void AddListener(string eventType, Action<T, U, V> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void AddListener<TReturn>(string eventType, Func<T, U, V, TReturn> handler) {
MessengerInternal.AddListener(eventType, handler);
}
static public void RemoveListener(string eventType, Action<T, U, V> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void RemoveListener<TReturn>(string eventType, Func<T, U, V, TReturn> handler) {
MessengerInternal.RemoveListener(eventType, handler);
}
static public void Broadcast(string eventType, T arg1, U arg2, V arg3) {
Broadcast(eventType, arg1, arg2, arg3, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, V arg3, Action<TReturn> returnCall) {
Broadcast(eventType, arg1, arg2, arg3, returnCall, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, T arg1, U arg2, V arg3, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Action<T, U, V>>(eventType);
foreach(var callback in invocationList)
callback.Invoke(arg1, arg2, arg3);
}
static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, V arg3, Action<TReturn> returnCall, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
var invocationList = MessengerInternal.GetInvocationList<Func<T, U, V, TReturn>>(eventType);
foreach(var result in invocationList.Select(del => del.Invoke(arg1, arg2, arg3)).Cast<TReturn>()) {
returnCall.Invoke(result);
}
}
}
MessengerUnitTest.cs
using System;
class MessengerUnitTest {
private readonly string eventType1 = "__testEvent1";
private readonly string eventType2 = "__testEvent2";
bool wasCalled = false;
public void RunTest() {
RunAddTests();
RunBroadcastTests();
RunRemoveTests();
Console.Out.WriteLine("All Messenger tests passed.");
}
private void RunAddTests() {
Messenger.AddListener(eventType1, TestCallback);
try {
Messenger<float>.AddListener(eventType1, TestCallbackFloat);
throw new Exception("Unit test failure - expected a ListenerException");
} catch (MessengerInternal.ListenerException e) {
}
Messenger<float>.AddListener(eventType2, TestCallbackFloat);
}
private void RunBroadcastTests() {
wasCalled = false;
Messenger.Broadcast(eventType1);
if (!wasCalled) { throw new Exception("Unit test failure - event handler appears to have not been called."); }
wasCalled = false;
Messenger<float>.Broadcast(eventType2, 1.0f);
if (!wasCalled) { throw new Exception("Unit test failure - event handler appears to have not been called."); }
Messenger<float>.Broadcast(eventType2 + "_", 1.0f, MessengerMode.DONT_REQUIRE_LISTENER);
try {
Messenger<float>.Broadcast(eventType1, 1.0f, MessengerMode.DONT_REQUIRE_LISTENER);
throw new Exception("Unit test failure - expected a BroadcastException");
}
catch (MessengerInternal.BroadcastException e) {
}
try {
Messenger<float>.Broadcast(eventType2 + "_", 1.0f);
throw new Exception("Unit test failure - expected a BroadcastException");
} catch (MessengerInternal.BroadcastException e) {
}
try {
Messenger<double>.Broadcast(eventType2, 1.0);
throw new Exception("Unit test failure - expected a BroadcastException");
} catch (MessengerInternal.BroadcastException e) {
}
}
private void RunRemoveTests() {
try {
Messenger<float>.RemoveListener(eventType1, TestCallbackFloat);
throw new Exception("Unit test failure - expected a ListenerException");
}
catch (MessengerInternal.ListenerException e) {
}
Messenger.RemoveListener(eventType1, TestCallback);
try {
Messenger.RemoveListener(eventType1, TestCallback);
throw new Exception("Unit test failure - expected a ListenerException");
}
catch (MessengerInternal.ListenerException e) {
}
Messenger<float>.RemoveListener(eventType2, TestCallbackFloat);
try {
Messenger<float>.RemoveListener(eventType2, TestCallbackFloat);
throw new Exception("Unit test failure - expected a ListenerException");
}
catch (MessengerInternal.ListenerException e) {
}
}
void TestCallback() {
wasCalled = true;
Console.Out.WriteLine("TestCallback() was called.");
}
void TestCallbackFloat(float f) {
wasCalled = true;
Console.Out.WriteLine("TestCallbackFloat(float) was called.");
if (f != 1.0f) {
throw new Exception("Unit test failure - wrong value on float argument");
}
}
}