[英]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.