为什么通用setter打破类型协方差,即使它受到约束?

时间:2016-07-22 12:41:27

标签: c#

我有以下界面:

public interface ICommand<TMessage> 
    where TMessage : MessageBase 
{
    TMessage Message { get; set; }
}

我希望能够将实现转换为IMessage,但为了实现这一点,type参数需要是协变的,如下所示:

public interface ICommand<out TMessage> 
    where TMessage : MessageBase 
{
    TMessage Message { get; set; }
}

然后,编译器抱怨:类型参数'TMessage'必须在ICommand.Message'上不变地有效。 'TMessage'是协变的。 如果我删除了setter,一切正常。

但是,我不明白为什么这个setter在理论上会出现问题,因为我已经指定Message属性只能保留对更多派生类型的MessageBase实例的引用...

1 个答案:

答案 0 :(得分:2)

没关系,经过多思考后,实际上很容易看到。

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

var derivedCommand = new DerivedCommand<DerivedMessage>();

然后将其投放到ICommand<MessageBase>

var command = (ICommand<MessageBase>) derivedCommand;

这意味着我现在可以将任何类型MessageBase的实例分配给Message属性。但是,由于该属性实际上是DerivedMessage类型,其派生的结果比MessageBase更多,因此它并不适用于所有情况(其中AnotherMessage派生自MessageBase但不是来自DerivedMessage > HISTTIMEFORMAT="%d/%m/%y %T " > history )。因此,即使类型受到约束,setter也不能协变。