我想创建一个通用机制来处理C#中的消息.我在我的小应用程序中需要这个,所以我不想使用完整的消息总线.我的要求很简单:
Message1,Message2.他们可以从一个基类继承,这不是问题,但如果不是,我不在乎.目前他们确实继承了Message.能够为每个消息类获取处理程序.即如果我发送Message1,那么Message1Handler应该实例化类.处理程序必须实现IMessageHandler<T>,其中T是消息类.IMessageHandler定义如下:
interface IMessageHandler<T>
{
void Execute(T message);
}
Run Code Online (Sandbox Code Playgroud)我写了一个简单的"解析器"类:
public static class HandlerRegistry
{
private static readonly Dictionary<string, Type> _handlers = new Dictionary<string, Type>();
public static void Register<T, T2>() where T2: IMessageHandler<T>
{
_handlers.Add(typeof(T).FullName, typeof(T2));
}
public static IMessageHandler<T> Resolve<T>(T parameters)
{
var type = _handlers[parameters.GetType().FullName];
return (IMessageHandler<T>) Activator.CreateInstance(type);
}
}
Run Code Online (Sandbox Code Playgroud)
在这个实现中,一切都很好,但是一部分 - 转换为IMessageHandler.当我试图将它与消息集合一起使用时,会发生这样的情况:编译器在编译时不知道集合中将会有什么实际消息 - 它只是假设它们都是子类Message,所以它是试图投射IMessageHandler<ConcreteMessage>到IMessageHandler<Message>显然我得到一个无效演员的异常.在这种情况下,可能的逆变会有所帮助,但我无法将参数声明为out,因为我在Execute方法参数中有消息.
有谁知道这个问题的优雅解决方案?我知道我可以使它"更加运行时" - 而不是使用泛型只是声明
void Execute(Message m)并且在每个处理程序中开始尝试强制转换为我期望的类型,但是有人说某处 - 你写的每一个演员破坏了使用类型系统的全部意义.
对于消息路由器来说怎么样:
class Tester
{
public void Go()
{
var a = new MessageA();
var b = new MessageB();
var c = new MessageC();
var router = new MessageRouter();
router.RegisterHandler(new HandlerA());
router.RegisterHandler(new HandlerB());
router.Route(a);
router.Route(b);
router.Route(c);
}
}
class MessageRouter
{
Dictionary<Type, dynamic> m_handlers = new Dictionary<Type,dynamic>();
public void RegisterHandler<T>(IMessageHandler<T> handler)
{
m_handlers.Add(typeof(T), handler);
}
public void Route(dynamic message)
{
var messageType = message.GetType();
if (m_handlers.ContainsKey(messageType))
{
m_handlers[messageType].Handle(message);
}
else
{
foreach (var pair in m_handlers)
{
if(pair.Key.IsAssignableFrom(messageType))
{
pair.Value.Handle(message);
}
}
}
}
}
class MessageA
{
public virtual string A { get { return "A"; } }
}
class MessageB
{
public string B { get { return "B"; } }
}
class MessageC :MessageA
{
public override string A { get { return "C"; } }
}
interface IMessageHandler<T>
{
void Handle(T message);
}
class HandlerA : IMessageHandler<MessageA>
{
public void Handle(MessageA message)
{
Console.WriteLine(message.A);
}
}
class HandlerB : IMessageHandler<MessageB>
{
public void Handle(MessageB message)
{
Console.WriteLine(message.B);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4837 次 |
| 最近记录: |