首先,您的问题的答案是否定的,C#不支持任何形式的虚拟覆盖类型的返回类型协方差。
许多回答者和评论者说“这个问题没有协方差”。这是不正确的。原始海报完全像他们一样提出问题。
回想一下,协变映射是保留了某些其他关系的存在和方向的映射。例如,从类型
T到类型的映射
IEnumerable<T>是协变的,因为它保留了分配兼容性关系。如果Tiger与Animal分配兼容,则地图下的变换也将保留:
IEnumerable<Tiger>分配与兼容
IEnumerable<Animal>。
这里的协变映射很难看,但仍然存在。本质上的问题是:这是否合法?
class B{ public virtual Animal M() {...}}class D : B{ public override Tiger M() {...}}老虎与动物兼容。现在,从类型T映射到方法“ public TM()”。 该映射是否保留兼容性 ?也就是说,
如果Tiger出于分配目的与Animal兼容,那么 为了虚拟覆盖而public Tiger M()
兼容public Animal M()
吗?
C#的答案是“否”。C#不支持这种协方差。
既然我们已经确定问题是使用正确的类型代数术语来提出的,那么对实际问题还有更多的想法。显而易见的第一个问题是,该属性甚至尚未被声明为虚拟属性,因此虚拟兼容性问题尚无定论。显而易见的第二个问题是“获取;设置;设置”;即使C#支持返回类型协方差,property属性也不是协变的,因为
带有setter的属性的类型不仅是其返回类型,而且还是其形式参数类型 。您需要 逆变
正式参数类型,实现类型安全。如果我们允许使用setter的属性返回类型协方差,那么您将:
class B{ public virtual Animal Animal{ get; set;}}class D : B{ public override Tiger Animal { ... }}B b = new D();b.Animal = new Giraffe();嘿,我们刚刚将一只长颈鹿送给了一只期待老虎的饲养员。如果我们支持此功能,则必须将其限制为返回类型(就像我们对通用接口的赋值-兼容性协方差所做的那样。)
第三个问题是CLR不支持这种差异。如果我们想以这种语言来支持它(就像我相信托管C
++那样),那么我们将不得不采取一些合理的措施来解决CLR中的签名匹配限制。
您可以通过仔细定义具有适合其基类类型的适当返回类型的“新”方法来自己采取这些英勇措施:
abstract class B { protected abstract Animal ProtectedM(); public Animal Animal { get { return this.ProtectedM(); } }}class D : B{ protected override Animal ProtectedM() { return new Tiger(); } public new Tiger Animal { get { return (Tiger)this.ProtectedM(); } }}现在,如果您有D的实例,您将看到Tiger型的属性。如果将其强制转换为B,则会看到Animal-
typed属性。无论哪种情况,您仍然可以通过受保护的成员获得虚拟行为。
简而言之,很抱歉,我们没有计划使用此功能。



