为什么协方差没有按预期工作?
Why is covariance not working as expected?
为什么这不起作用?编译器应该足够聪明,知道 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; }
}
这是为什么?
The compiler should be smart enough to know that InterfaceB requires InterfaceA and therefore must be compatible.
但它不兼容 - 你可以这样做:
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; }
}
我承认我还没有深入研究 C# 9,但据我所知,协变 returns 仅适用于 方法 和 只获取 属性。如果是这种情况,您的解决方案就可以了。在这种情况下,是 setter 允许您打破类型系统。
似乎还支持 只读 属性,因此您可以这样做:
public abstract class DerivedClass : BaseClass
{
protected override InterfaceB ItemService { get; }
}
public abstract class BaseClass
{
protected virtual InterfaceA ItemService { get; }
}
基础 class 表示任何 InterfaceA 都可以分配给 ItemService,因此派生 class 不能将其更改为“只能将 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; }
}
它会起作用,因为没有分配......但我不确定你的实际目标
为什么这不起作用?编译器应该足够聪明,知道 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; }
}
这是为什么?
The compiler should be smart enough to know that InterfaceB requires InterfaceA and therefore must be compatible.
但它不兼容 - 你可以这样做:
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; }
}
我承认我还没有深入研究 C# 9,但据我所知,协变 returns 仅适用于 方法 和 只获取 属性。如果是这种情况,您的解决方案就可以了。在这种情况下,是 setter 允许您打破类型系统。
似乎还支持 只读 属性,因此您可以这样做:
public abstract class DerivedClass : BaseClass
{
protected override InterfaceB ItemService { get; }
}
public abstract class BaseClass
{
protected virtual InterfaceA ItemService { get; }
}
基础 class 表示任何 InterfaceA 都可以分配给 ItemService,因此派生 class 不能将其更改为“只能将 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; }
}
它会起作用,因为没有分配......但我不确定你的实际目标