为什么泛型setter会破坏类型协方差,即使它受到约束
本文关键字:约束 方差 setter 泛型 类型 为什么 | 更新日期: 2023-09-27 17:58:17
我有以下接口:
public interface ICommand<TMessage>
where TMessage : MessageBase
{
TMessage Message { get; set; }
}
我希望能够将实现强制转换为IMessage,但为了实现这一点,类型参数需要是协变的,如下所示:
public interface ICommand<out TMessage>
where TMessage : MessageBase
{
TMessage Message { get; set; }
}
但是,编译器抱怨道:类型参数"TMessage"在ICommand上必须是不变有效的。消息"."TMessage"是协变的。如果我去掉setter,一切都会很好。
然而,我不明白为什么这个setter在理论上会带来问题,因为我已经指定Message属性只能引用更多派生类型的MessageBase的实例。。。
没关系,仔细考虑一下,它实际上很容易看到。
假设我实例化一个DerivedCommand<T>
(实现ICommand<T>
)
var derivedCommand = new DerivedCommand<DerivedMessage>();
然后将其投射到ICommand<MessageBase>
var command = (ICommand<MessageBase>) derivedCommand;
这意味着我现在可以将任何类型为MessageBase
的实例分配给Message属性。但是,由于该属性的类型实际上是DerivedMessage
,它比MessageBase
派生得更多,因此它并不适用于所有情况(其中AnotherMessage
确实从MessageBase
派生,但不是从DerivedMessage
派生)。因此,即使类型受到约束,setter也不能是协变的。