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

问题描述 投票:0回答:1

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

该服务的肉和土豆归结为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是处理程序接受的特定类型。

当在组件之间发送消息(进行中)时,一切都很有效,因为消息的类型(通常)在编译时是已知的,因此它的类型可以是特定的(I.E.不是所有消息继承的基本Message类)

但是,我需要支持通过网络到达的消息。它们在标题中以类型代码序列化。所以直到运行时才能知道什么类型的消息将到达。

简单地说,当消息通过网络到达时,TMessage方法中的HandleMessageMessage类型,而不是反序列化的特定消息类型。

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

有什么办法可以“强制”将泛型类型作为消息的特定类型吗?

c# generics delegates
1个回答
0
投票

尝试通过对泛型的约束使TMessage属于BrokeredMessage类型,然后使用:

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

得到实际的类型。

© www.soinside.com 2019 - 2024. All rights reserved.