简体   繁体   English

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

[英]What is the best way to create a simple global event system in C#?

I'm looking to create a quick event system in C# but I'm not sure the best way to approach it. 我想在C#中创建一个快速事件系统,但我不确定接近它的最佳方法。 Here's how I would like it to work: 以下是我希望它的工作方式:

Messenger 信使

This is where I'd like all events to be stored. 这是我希望存储所有事件的地方。 The class would look something like this: 该类看起来像这样:

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;
}

Subscribers 认购

I'd like anything to be able to subscribe to these messages by doing something like this: 我希望通过这样的方式能够订阅这些消息:

// 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);

Dispatchers 调度员

Finally, I'd like anything to be able to dispatch any of these events like so: 最后,我希望能够发送任何这样的事件,如下所示:

Messenger.OnGameStarted(gameState, ammoCount, livesCount);

// or

Messenger.OnGameStarted.Invoke(gameState, ammoCount, livesCount);

Is there any way to do something like this easily and cleanly? 有没有办法轻松干净地做这样的事情? I'd like for it to be very fast to create new events (without having to create new classes or any boilerplate code) 我希望它能够非常快速地创建新事件(无需创建新类或任何样板代码)

Basically The Messenger class would act as a central hub for specific events, something that can easily be referenced and managed from a single location. 基本上, Messenger类将充当特定事件的中心枢纽,可以从单个位置轻松引用和管理。

I would suggest using the standard .NET events mechanism. 我建议使用标准的.NET事件机制。 You need both the event declaration and the raising method to reside inside the static class, because external code is allowed only to subscribe/unsubscribe to the events (directly). 您需要事件声明和raise方法驻留在静态类中,因为外部代码只允许订阅/取消订阅事件(直接)。

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

The null conditional operator ?. 空条件运算符?. is required because events without subscriptions are null references. 是必需的,因为没有订阅的事件是空引用。 It also takes care of race conditions in multithreaded scenarios. 它还可以处理多线程场景中的竞争条件。


Update: Regarding memory leaks, every time that an object subscribes to an event of another object, a connection is created between the two objects. 更新:关于内存泄漏,每次对象订阅另一个对象的事件时,都会在两个对象之间创建连接。 The basic principal is: 基本原则是:

The subscribers don't keep references of publishers. 订阅者不保留发布者的引用。 Only the publishers keep references of subscribers. 只有发布者保留订阅者的引用。

This means that long-lived publishers may prevent short-lived subscribers from being garbage collected. 这意味着长期存在的发布者可能会阻止短期订阅者进行垃圾回收。 This is something to have in mind when subscribing to an event. 订阅活动时需要注意这一点。 Is the publisher expected to out-live me? 出版商是否应该超过我? If the answer is yes, then I must unsubscribe before I die. 如果答案是肯定的,那么在我死之前我必须取消订阅。 In the specific case the publisher is a static class, that will never be garbage collected, so all objects with a life-span shorter that the life-span of the application should unsubscribe from the static events they subscribed earlier. 在特定情况下,发布者是一个静态类,永远不会被垃圾收集,因此所有具有生命周期的对象都会缩短,以至于应用程序的生命周期应该取消订阅他们之前订阅的静态事件。 Otherwise memory leaks will occur. 否则会发生内存泄漏。 Here is an example of subscribing-unsubscribing: 以下是订阅取消订阅的示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在全局事件中使用c#处理事件的开始和结束时间的最佳方法是什么 - What's the best way of handling begin and end times for an event in c# where the events are global 在C#中实现全局常量的最佳方法是什么? - What's the best way to implement a global constant in C#? 在C#2.0中创建向导的最佳方法是什么? - What is the best way to create a wizard in C# 2.0? 在C#中创建连接类的最佳方法是什么 - what is the best way to create connection Class in C# C#创建被多个类使用的枚举的最佳方法是什么? - C# What is the best way to create an enum that is used by multiple classes? 更改系统语言的最佳方法 c# - The best way to change system language c# 侦听C#中事件的最佳方法 - Best way to listen for an event in c# 在C#中实现标记系统的最佳方法是什么(没有数据库;没有asp.net)? - What is the best way of implementing tagging system in C# (no database; no asp.net)? 将i18n添加到现有的自定义CMS系统(使用C#构建)的最佳方法是什么? - What is the best way to add i18n to an existing custom CMS system (build with C#)? 在c#中实现队列的最佳方法是什么(System.Collection.Queue有内存限制) - What is best way to implement a queue in c#(System.Collection.Queue has memory limitation)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM