用C#创建简单的全局事件系统的最佳方法是什么?

时间:2019-04-30 01:35:06

标签: c# .net design-patterns

我正在寻找用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类将充当特定事件的中心枢纽,可以轻松地从单个位置进行引用和管理。

1 个答案:

答案 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
    }
}