我正在寻找用C#创建一个快速事件系统,但是我不确定实现它的最佳方法。这是我希望它起作用的方式:
信使
这是我想要存储所有事件的地方。该类如下所示:
public static class Messenger
{
// This event would have a few params, like GameState, Ammo, and Lives, or something
public static GameStateMessage OnGameStateChanged;
// This event could be generic, with no args
public static Message OnGameStarted;
}
订户
我希望通过以下操作可以订阅这些消息:
// Handler, which will be passed to the event
private void OnGameStartedHandler(GameState gameState, int ammo, int lives)
{
// Do something
}
// Event would be subscribed to like this:
Messenger.OnGameStarted += OnGameStartedHandler;
// or this:
Messenger.OnGameStarted.Subscribe(OnGameStartedHandler);
调度程序
最后,我希望任何事情都可以像这样发送这些事件:
Messenger.OnGameStarted(gameState, ammoCount, livesCount);
// or
Messenger.OnGameStarted.Invoke(gameState, ammoCount, livesCount);
有什么方法可以轻松,干净地完成这样的事情吗?我希望它能很快创建新事件(而不必创建新类或任何样板代码)
基本上,Messenger
类将充当特定事件的中心枢纽,可以轻松地从单个位置进行引用和管理。
答案 0 :(得分:0)
我建议使用标准的.NET事件机制。您需要将事件声明和升高方法都驻留在静态类中,因为只允许外部代码(直接)订阅/取消订阅事件。
public static class Messenger
{
public static event Action<GameStateMessage> GameStateChanged;
public static void OnGameStateChanged (GameStateMessage arg) => GameStateChanged?.Invoke(arg);
public static event Action<Message> GameStarted;
public static void OnGameStarted (Message arg) => GameStarted?.Invoke(arg);
}
Messenger.GameStarted += (Message arg) => // Subscribing to the event
{
Console.WriteLine(arg);
};
Messenger.OnGameStarted(new Message("Get ready!")); // Raising the event
空条件运算符?.
是必需的,因为没有订阅的事件是空引用。它还照顾了多线程方案中的竞争条件。
更新:关于内存泄漏,每当一个对象订阅另一个对象的事件时,就会在两个对象之间创建一个连接。基本原理是:
订阅者不保留发布者的引用。只有发布者保留订户的引用。
这意味着寿命长的发布者可能会阻止垃圾回收短寿命的订阅者。订阅事件时要牢记这一点。出版商会比我活得更长寿吗?如果答案是肯定的,那么我必须在死前退订。在特定情况下,发布者是静态类,它将永远不会被垃圾回收,因此所有具有较短寿命的对象都比应用程序的寿命短,应取消订阅他们之前订阅的静态事件。否则会发生内存泄漏。这是一个订阅-取消订阅的示例:
public class Player : IDisposable
{
public Player() // Constructor
{
Messenger.GameStarted += Messenger_GameStarted; // Subscribe
}
private void Messenger_GameStarted(Message arg) // Event handler
{
Console.WriteLine(arg);
}
public void Dispose() // This method must be called when the object is about to perish
{
Messenger.GameStarted -= Messenger_GameStarted; // Unsubscribe
}
}