似乎无法让通用 Covariance/Contravariance 工作
Can't seem to get Generic Covariance/Contravariance to work
假设我有以下代码:
public interface IBaseMessage { }
public interface IMessageProcessor<in T> where T : IBaseMessage {
void Process(T msg);
}
public class RRMessage : IBaseMessage {
//something here
}
public class BaseMessageProcessor {
//something here
}
public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessor<RRMessage> {
public void Process(RRMessage msg) {
Console.WriteLine("Processed RRMessage");
}
}
public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>();
[Test]
public void Test1() {
var msgProcessor = new RRMessageProcessor();
MessageProcessors.Add(typeof(RRMessage), msgProcessor);
}
我为接口 IMessageProcessor 启用了逆变。为什么MessageProcessors.Add(typeof(RRMessage), msgProcessor);
会导致编译时错误:
Argument 2: cannot convert from 'RRMessageProcessor' to
'IMessageProcessor<IBaseMessage>'
它似乎应该能够转换,因为 RRMessageProcessor:IMessageProcessor<RRMessage:IBaseMessage>>
我怎样才能让它工作?
IMessageProcessor<in T>
在T
中是逆变的,不是协变的。这意味着允许以下内容:
class RRSubtype : RRMessage {}
IMessageProcessor<RRSubtype> p = new RRMessageProcessor();
您尝试做的事情在静态上是不安全的,因为它允许您:
class NotRRMessage : IBaseMessage { }
IMessageProcessor<IBaseMessage> p = new RRMessageProcessor();
p.Process(new NotRRMessage());
所以你需要动态地维护安全,你似乎正在尝试使用字典 Type -> Processor
。因此,您可以创建一个不安全的包装器类型:
public class ProcessorWrapper<T> : IMessageProcessor<IBaseMessage> {
private readonly IMessageProcessor<T> inner;
public ProcessorWrapper(IMessageProcessor<T> inner) { this.inner = inner; }
public void Process(IBaseMessage msg)
{
if(msg is T) { inner.Process((T)msg); }
else throw new ArgumentException("Invalid message type");
}
}
然后您可以使用这些包装器构建您的列表,同时维护您想要输入的内部处理器,例如
public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>();
MessageProcessors.Add(new ProcessorWrapper<RRMessage>(new RRMessageProcessor());
假设我有以下代码:
public interface IBaseMessage { }
public interface IMessageProcessor<in T> where T : IBaseMessage {
void Process(T msg);
}
public class RRMessage : IBaseMessage {
//something here
}
public class BaseMessageProcessor {
//something here
}
public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessor<RRMessage> {
public void Process(RRMessage msg) {
Console.WriteLine("Processed RRMessage");
}
}
public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>();
[Test]
public void Test1() {
var msgProcessor = new RRMessageProcessor();
MessageProcessors.Add(typeof(RRMessage), msgProcessor);
}
我为接口 IMessageProcessor 启用了逆变。为什么MessageProcessors.Add(typeof(RRMessage), msgProcessor);
会导致编译时错误:
Argument 2: cannot convert from 'RRMessageProcessor' to 'IMessageProcessor<IBaseMessage>'
它似乎应该能够转换,因为 RRMessageProcessor:IMessageProcessor<RRMessage:IBaseMessage>>
我怎样才能让它工作?
IMessageProcessor<in T>
在T
中是逆变的,不是协变的。这意味着允许以下内容:
class RRSubtype : RRMessage {}
IMessageProcessor<RRSubtype> p = new RRMessageProcessor();
您尝试做的事情在静态上是不安全的,因为它允许您:
class NotRRMessage : IBaseMessage { }
IMessageProcessor<IBaseMessage> p = new RRMessageProcessor();
p.Process(new NotRRMessage());
所以你需要动态地维护安全,你似乎正在尝试使用字典 Type -> Processor
。因此,您可以创建一个不安全的包装器类型:
public class ProcessorWrapper<T> : IMessageProcessor<IBaseMessage> {
private readonly IMessageProcessor<T> inner;
public ProcessorWrapper(IMessageProcessor<T> inner) { this.inner = inner; }
public void Process(IBaseMessage msg)
{
if(msg is T) { inner.Process((T)msg); }
else throw new ArgumentException("Invalid message type");
}
}
然后您可以使用这些包装器构建您的列表,同时维护您想要输入的内部处理器,例如
public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>();
MessageProcessors.Add(new ProcessorWrapper<RRMessage>(new RRMessageProcessor());