Каков наилучший способ создания простой глобальной системы событий в C #? - PullRequest
0 голосов
/ 30 апреля 2019

Я хочу создать быструю систему событий в C #, но я не уверен, что лучший способ приблизиться к ней.Вот как я хотел бы, чтобы это работало:

Messenger

Здесь я хочу, чтобы все события были сохранены.Класс будет выглядеть примерно так:

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

IsЕсть ли способ сделать что-то подобное легко и чисто?Я бы хотел, чтобы это было очень быстро для создания новых событий (без необходимости создавать новые классы или какой-либо шаблонный код)можно легко ссылаться и управлять из одного места.

1 Ответ

0 голосов
/ 30 апреля 2019

Я бы предложил использовать стандартный механизм событий .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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...