如何在运行时指定泛型类型?

How to specify generic types at runtime?

我有一段代码是这样的:

  var senders = new List<MessageSenderBase<object>>();
  senders.Add(new MessageSender1<MessageType1>());

其中 MessageSender1<MessageType1> 派生自 MessageSenderBase<T>MessageType1 是我定义的另一个 class。

现在第二行出现错误 CS1503 Argument 1: cannot convert from 'Demo.MessageSender.MessageSender1<Demo.MessageSender.MessageType1>' to 'Demo.MessageSender.MessageSenderBase<object>'

我该如何解决这个问题?

我的设计是 MessageSenderBase<T> 将放在我的库中,在 API 级别,用户可以派生他们自己的发件人 class 并指定他们想要的消息类型发送。我认为这会起作用,因为 objectMessageType1 的基数 class,而 MessageSenderBase<>MessageSender1<> 的基数 class。

请帮忙,谢谢!

编辑 - 添加 MessageSenderBase

    public class MessageSender1<MessageType1> : MessageSenderBase<MessageType1>
    {
        public override string Topic => "topic1";

        public async override Task SendAsync()
        {
            //...
        }
    }

    public abstract class MessageSenderBase<T>
    {
        public abstract string Topic { get;}
        public T Deserialize(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }
        public abstract Task SendAsync();
    }

解决此问题的一种方法是添加一个新的 covariant 界面,其“形状”为 MessageSenderBase<T>:

public interface IMessageSender<out T> {
    string Topic { get; }
    T Deserialize(string json);
    Task SendAsync();
}
public abstract class MessageSenderBase<T>: IMessageSender<T>
{
    public abstract string Topic { get;}
    public T Deserialize(string json)
    {
        return JsonConvert.DeserializeObject<T>(json);
    }
    public abstract Task SendAsync();
}

如果您现在将列表设为 List<IMessageSender<object>> 类型,则可以将 AnyMessageSender<AnythingReferenceType> 放入其中。

var senders = new List<IMessageSender<object>>();
senders.Add(new MessageSender1<MessageType1>());

请注意,如果 MessageSenderBase 有一个以 T 作为参数的方法(或者更一般地说,在“输入位置”有一个 T),你不应该包括在 IMessageSender 中,因为如果这样做,从 MessageSender1<MessageType1> 转换为 IMessageSender<object> 不再安全。想象一下,如果您有:

public interface IMessageSender<out T> {
    ...
    void Foo(T someT); // suppose this is implemented in MessageSender1
}

你可以做到:

var senders = new List<IMessageSender<object>>();
senders.Add(new MessageSender1<MessageType1>());
senders[0].Foo("abc"); // let's try giving a string to Foo

但是 senders[0] 是一个 MessageSender1<MessageType1> 对象。 MessageSender1<MessageType1>.Foo 只接受 MessageType1 个对象,不接受字符串!