【问题标题】:Strongly-typed Message Handlers in Mediator in C#C# Mediator 中的强类型消息处理程序
【发布时间】:2020-01-13 01:15:05
【问题描述】:

我目前在当前项目中实施对象间通信解决方案时遇到问题。我决定尝试像中介者模式这样的对象,其中对象通过向中介者广播使用消息相互通信。然后中介者将消息发送给专门监听正在广播的消息的对象。

我以前使用的中介对象依赖于将容器保存到仅处理基本消息的处理程序中,这迫使侦听器在处理消息之前强制转换消息。我想我可以通过根据某种任意类型将处理程序集合本身放在一个键控集合中来解决这个问题。通过这样做,我希望避免听众为响应消息而必须做的任何类型的投射。

问题是,我似乎无法理解如何获取允许其他人注册强类型消息的对象,以维护不同类型强类型消息处理程序的单个集合。

理想情况下,我希望面向公众的界面如下所示:

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

这种设计是否可以实现我想要的强类型消息处理?如果是这样,我该怎么做?

编辑 - 添加代码来描述我希望发送者和接收者对象如何与方法交互。

【问题讨论】:

  • 如果您希望注册的处理程序保留在一个集合/地图中,您需要将它们转换为某种通用类型以便保存并在使用时转换回
  • 提供更多你想做的代码
  • 我添加了一个接收对象和发送对象的例子。如果你想要更具体的东西,我想我需要一个比你给出的更具体的要求。

标签: c# generics design-patterns mediator


【解决方案1】:

可能最好的方法是查看 Mediatr 如何实现该模式,因为它是用于 Mediator 模式/应用内消息传递的最流行的 C# 库。

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

简而言之,它包含“NotificationHandlerWrapperImpl”的包装对象列表。但是它将它们保存在一个对象列表中(这样您就可以解决 Action vs Action vs Action 铸造问题)。

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

该包装器的实际实现相当简单:https://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/

【讨论】:

    猜你喜欢
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    相关资源
    最近更新 更多