在将对象作为通用参数传递时如何使用对象的基础类型

时间:2018-09-02 04:15:31

标签: c# generics delegates

我有一个消息代理服务,该服务从代码中的各个组件分派消息。它依赖于一个属性,该属性定义哪些方法处理哪些消息。

服务的实质归结为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是处理程序接受的特定类型

在组件之间(进行中)发送消息时,一切正常,因为消息的类型(通常)在编译时是已知的,因此它的类型可以是特定的(即不是所有的基类Message消息继承自)

但是,我需要支持通过网络到达的消息。它们以标头中的类型代码序列化到达。因此,没有办法直到运行时才知道哪种消息类型。

简而言之,当消息通过网络到达时,TMessage方法中的HandleMessage类型为Message,而 not specific < / em>已反序列化的消息类型。

这会导致模式匹配(if (handler is Action<TSender, TMessage> h))失败并迫使我使用DynamicInvoke

有什么办法可以“强制”通用类型为消息的特定类型?

1 个答案:

答案 0 :(得分:0)

通过对通用消息的约束,使TMessage的类型为BrokeredMessage,然后使用:

var ct = brokeredMessage.ContentType;
Type bodyType = Type.GetType(ct, true);

获取实际类型。