【发布时间】:2019-02-07 13:50:51
【问题描述】:
我有一个消息代理服务,它从代码中的各个组件分派消息。它依赖于一个属性,该属性定义了哪些方法处理哪些消息。
服务的肉和土豆归结为HandleMessage方法:
private void HandleMessage<TMessage, TSender>(TMessage message, TSender sender = null) where TMessage : Message where TSender : class
{
var messageType = message.GetType();
if (messageHandlers.TryGetValue(messageType, out List<Delegate> handlers))
{
foreach (var handler in handlers)
{
try
{
if (handler is Action<TSender, TMessage> h)
ThreadPool.QueueUserWorkItem(x => h.Invoke(sender, message));
else
{
ThreadPool.QueueUserWorkItem(x => handler.DynamicInvoke(sender, message));
}
}
catch(Exception e)
{
log?.LogError($"Attempt to handle a message failed. {e.Message}");
}
}
}
else
{
log?.LogError(string.Format("No handler found for message of type {0}", messageType.FullName));
throw new NoHandlersException(messageType.FullName);
}
}
对我来说很重要的一个特性是不必在处理程序方法本身中强制发送发送者或消息,所以当处理程序被“注册”时,它注册为Action<T1,T2>,其中 T1 和 2 是处理程序接受的特定类型。
当在组件之间(在进程中)发送消息时,一切都很好,因为消息的类型(通常)在编译时是已知的,因此它的类型可以是特定的(IE 不是所有消息继承的基本 Message 类来自)
但是,我需要支持通过网络到达的消息。它们在标题中使用类型代码序列化。所以没有办法直到运行时才知道什么类型的消息会到达。
简单地说,当一条消息通过网络到达时,HandleMessage 方法中的TMessage 是Message 类型,不是特定消息类型已反序列化。
这会导致模式匹配 (if (handler is Action<TSender, TMessage> h)) 失败并迫使我使用 DynamicInvoke。
有什么方法可以“强制”将泛型类型“强制”为消息的特定类型?
【问题讨论】: