为什么泛型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的实例。。。

为什么泛型setter会破坏类型协方差,即使它受到约束

没关系,仔细考虑一下,它实际上很容易看到。

假设我实例化一个DerivedCommand<T>(实现ICommand<T>

var derivedCommand = new DerivedCommand<DerivedMessage>();

然后将其投射到ICommand<MessageBase>

var command = (ICommand<MessageBase>) derivedCommand;

这意味着我现在可以将任何类型为MessageBase的实例分配给Message属性。但是,由于该属性的类型实际上是DerivedMessage,它比MessageBase派生得更多,因此它并不适用于所有情况(其中AnotherMessage确实从MessageBase派生,但不是从DerivedMessage派生)。因此,即使类型受到约束,setter也不能是协变的。