运行时指定泛型类型遇到CS1503转换错误该如何解决?
问题根因
你遇到的编译错误是C#泛型的不变性特性导致的:默认情况下,就算T是U的子类,GenericClass<T>也不会被视为GenericClass<U>的子类,哪怕U是所有类型的基类object也不例外。
C#仅支持接口和委托的协变/逆变,泛型类本身完全不支持协变,所以你的MessageSenderBase<MessageType1>无法直接转换为MessageSenderBase<object>。
解决方案
以下两种方案都可以满足你封装类库、允许用户自定义派生发送器和消息类型的需求:
方案1:抽取非泛型公共接口(最常用)
把所有和泛型参数T无关的公共成员提取到一个非泛型接口中,集合直接存储这个接口类型的实例即可。
步骤1:定义非泛型公共接口
public interface IMessageSender { string Topic { get; } Task SendAsync(); }
步骤2:修改泛型基类实现该接口
public abstract class MessageSenderBase<T> : IMessageSender { public abstract string Topic { get;} public T Deserialize(string json) { return JsonConvert.DeserializeObject<T>(json); } public abstract Task SendAsync(); }
步骤3:修改集合类型
var senders = new List<IMessageSender>(); // 可正常添加任意派生的发送器实例 senders.Add(new MessageSender1<MessageType1>()); senders.Add(new MessageSender2<MessageType2>());
该方案完全不影响用户侧的派生逻辑,你封装类库时仅需额外新增一个公共接口即可。
方案2:使用协变泛型接口(保留反序列化能力)
如果你需要在集合侧调用Deserialize方法获取返回值,可以用带协变标记的泛型接口:
步骤1:定义协变泛型接口
// 类型参数前加out标记为协变,仅允许T作为返回值类型 public interface IMessageSender<out T> { string Topic { get; } T Deserialize(string json); Task SendAsync(); }
步骤2:修改泛型基类实现该接口
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(); }
步骤3:修改集合类型
var senders = new List<IMessageSender<object>>(); // 协变支持下可正常转换 senders.Add(new MessageSender1<MessageType1>()); // 调用Deserialize返回object类型 object msg = senders[0].Deserialize(jsonStr);
该方案仅在你需要统一调用集合内实例的Deserialize方法时使用。
内容的提问来源于stack exchange,提问作者Joey Zhou
相关产品推荐
相关产品推荐

