C# 为什么协方差不能按预期工作?

C# 为什么协方差不能按预期工作?,c#,c#-9.0,C#,C# 9.0,为什么这不起作用?编译器应该足够聪明,知道InterfaceB需要InterfaceA,因此必须兼容 public interface InterfaceA { } public interface InterfaceB : InterfaceA { } public abstract class DerivedClass : BaseClass { protected override InterfaceB ItemService { get; set; } // Error, n

为什么这不起作用?编译器应该足够聪明,知道InterfaceB需要InterfaceA,因此必须兼容

public interface InterfaceA
{ }

public interface InterfaceB : InterfaceA
{ }

public abstract class DerivedClass : BaseClass
{
    protected override InterfaceB ItemService { get; set; } // Error, needs to be InterfaceA
}

public abstract class BaseClass
{
    protected virtual InterfaceA ItemService { get; set; }
}
为什么呢

编译器应该足够聪明,知道InterfaceB需要InterfaceA,因此必须兼容

public interface InterfaceA
{ }

public interface InterfaceB : InterfaceA
{ }

public abstract class DerivedClass : BaseClass
{
    protected override InterfaceB ItemService { get; set; } // Error, needs to be InterfaceA
}

public abstract class BaseClass
{
    protected virtual InterfaceA ItemService { get; set; }
}
但它不兼容-您可以这样做:

DerivedClass derived = new DerivedClass();
InterfaceB ib = new InterfaceBImpl(); 
derived.ItemService = ib;              // good so far
InterfaceA ia = new InterfaceAImpl();  // still good
BaseClass bc = derived;                // still a legal downcast
bc.ItemService = ia;                   // seemingly good - BaseClass can store an InterfaceA
ib = derived.ServiceImpl;
这就是它爆炸的地方。您已将未实现InterfaceB的对象存储在需要
InterfaceB
的属性中

实现所需功能的一种常见方法仍然是泛型:

public abstract class DerivedClass : BaseClass<InterfaceB>
{
    //protected override InterfaceB ItemService { get; set; } // Error, needs to be InterfaceA
    // no override needed - ItemService will now be of type InterfaceB
}

public abstract class BaseClass<T> where T : InterfaceA
{
    protected T ItemService { get; set; }
}

基类表示任何InterfaceA都可以分配给ItemService,因此派生类不能将其更改为“只能将InterfaceB分配给它”。但是如果你放弃了任务,那么它就是:-

  public interface InterfaceB : InterfaceA
    {
    }

    public abstract class DerivedClass : BaseClass
    {
        protected override InterfaceB ItemService { get; } // no set
    }

    public abstract class BaseClass
    {
        protected virtual InterfaceA ItemService { get; }

    }

它会起作用,因为没有任务……但我不确定你的实际目标

你不能更改合同,而且这也没有意义。。。与
BaseClass-derived=new-DerivedClass()一样
您可以分配非
接口b
的内容,如
派生。ItemService=instanceOfImplementationOfInterfaceAAndNotInterfaceB通过基类,您可以将任何interfaceA分配给可能未实现interfaceB的“ItemService”…答案自2009年以来没有改变-。。。正如@Selvin所指出的,问题中显示的示例没有意义——无法更改get和set的类型,也无法支持方差(co-或contra-)。你可能有理由期待它与get或set一起工作……”但从我所看到的情况来看,协变返回只适用于方法。“不,两者都适用。返回类型协方差仅适用于仅获取属性或方法,这是有意义的。协方差仅允许用于仅返回的类型。setter违反此规则。谢谢你指出这一点。是的,因为设置变量可以通过不同的方式完成,比如在派生类中重写get-only属性仍然可以由构造函数设置,我同意这一点。谢谢