Обработчики сообщений со строгой типизацией в посреднике на C #

В настоящее время у меня возникла проблема с реализацией решения для межобъектного взаимодействия в моем текущем проекте. Я решил опробовать такой объект, как шаблон посредника, где объекты общаются друг с другом с помощью сообщений через широковещательную рассылку посреднику. Затем посредник отправляет сообщение объектам, которые специально прослушали транслируемое сообщение.

Предыдущие объекты-посредники, которые я использовал, основывались на хранении контейнеров для обработчиков, обрабатывающих только базовое сообщение, вынуждая слушателей передавать сообщения, прежде чем они смогут их обработать. Я думал, что смогу обойтись с этим, имея коллекции самих обработчиков в коллекции с ключами в соответствии с каким-то произвольным типом. Поступая так, я надеюсь избежать какого-либо преобразования, которое должен выполнить слушатель, чтобы ответить на сообщение.

Проблема в том, что я не могу понять, как получить объект, который позволяет другим регистрироваться для строго типизированного сообщения, чтобы поддерживать единую коллекцию различных типов строго типизированных обработчиков сообщений.

В идеале я бы хотел, чтобы общедоступный интерфейс выглядел следующим образом:

class Mediator
{
    private Dictionary<Type, ???> handlers; // how to I retain the strongly-typed handler


    public void RegisterForBroadcast<T>(Action<T> handler) where T : IMessage
    {
        // how can I turn the strongly-typed handler into something I can use?
    }

    public void UnregisterFromBroadcast<T>(Action<T> handler) where T : IMessage
    {
    }

    public void Broadcast<T>(T message) where T : IMessage
    {
        // how do I get the collection of handlers from where it's stored and use it?
    }
}

class Receiver
{
     private Mediator mediator; 

     public Receiver()
     { 
          mediator = GetMediator();
          mediator.RegisterForBroadcast<SpecificMessage>(MessageHandler);
     }

     private void MessageHandler(SpecificMessage msg)
     {
          CustomData data = msg.GetCustomData();
     }
}

class BroadcastingObject
{
     private Mediator mediator;
     private SpecificData data;

     public BroadcastingObject()
     {
          mediator = GetMediator();
          specificData = GetSpecificData();
     }

     public void TimeToBroadcast()
     {
          mediator.Broadcast<SpecificMessage>(new SpecificMessage(specificData));
     }
}

Возможно ли с этим дизайном иметь строго типизированную обработку сообщений, которую я хочу? Если да, то как мне это сделать?

Изменить - добавлен код, описывающий, как объект отправителя и получателя должен взаимодействовать с методами.


person NChamp    schedule 13.01.2020    source источник
comment
Если вы хотите, чтобы зарегистрированные обработчики хранились в одной коллекции / карте, вам нужно преобразовать их в какой-то общий тип для сохранения и вернуть обратно при их использовании.   -  person Fabio    schedule 13.01.2020
comment
предоставьте больше кода того, что вы хотите сделать   -  person Asım Gündüz    schedule 17.01.2020
comment
Я добавил пример объекта-получателя и объекта-отправителя. Если вам нужно что-то более конкретное, я думаю, мне понадобится более конкретный запрос, чем то, что вы дали.   -  person NChamp    schedule 18.01.2020


Ответы (1)


Вероятно, лучше всего было бы посмотреть, как Mediatr реализует шаблон, поскольку это самая популярная библиотека C # для шаблона Mediator / в обмене сообщениями приложений.

https://github.com/jbogard/MediatR/blob/master/src/MediatR/Mediator.cs

Короче говоря, он содержит список объектов оболочки «NotificationHandlerWrapperImpl». Но он хранит их в списке объектов (чтобы вы обошли проблемы с приведением типов действий против действий против действий).

private static readonly ConcurrentDictionary<Type, object> _requestHandlers = new ConcurrentDictionary<Type, object>();

Фактическая реализация этой оболочки довольно проста: rel="noreferrer.cs"> //github.com/jbogard/MediatR/blob/e8833143c0742bdf72a6c6f104ef1dfadb59bf42/src/MediatR/Internal/NotificationHandlerWrapper.cs

Он в основном использует шаблон локатора сервисов для получения экземпляров IHandler:

var handlers = serviceFactory
    .GetInstances<INotificationHandler<TNotification>>()
    .Select(x => new Func<INotification, CancellationToken, Task>((theNotification, theToken) => x.Handle((TNotification)theNotification, theToken)));

Mediatr на самом деле довольно прост, и я настоятельно рекомендую загрузить исходный код, если вы хотите собрать и извлечь фрагменты для создания своего собственного. В противном случае просто используйте сам Mediatr, так как в большинстве случаев этого будет достаточно, и вам не нужно кататься самостоятельно! Краткое руководство по началу работы здесь: https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-part-3-mediatr-library/

person MindingData    schedule 25.02.2020