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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在将对象作为泛型参数传递时使用它的基础类型相关的知识,希望对你有一定的参考价值。

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

该服务的肉和土豆归结为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

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

答案

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

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

得到实际的类型。

以上是关于如何在将对象作为泛型参数传递时使用它的基础类型的主要内容,如果未能解决你的问题,请参考以下文章

默认泛型可作为参数正常使用,但不能作为函数参数的返回类型使用

关于泛型,什么是泛型,如何理解泛型,直接上代码举例

Java基础:泛型详解

引用类型用法总结

C#如何将类型Type作为泛型T的参数T传递

编写高质量代码改善C#程序的157个建议——建议97:优先考虑将基类型或接口作为参数传递