我可以覆盖派生类型吗?
据我所知,不可能在C2.0中执行以下操作
public class Father { public virtual Father SomePropertyName { get { return this; } } } public class Child : Father { public override Child SomePropertyName { get { return this; } } }
我通过在派生类中将属性创建为" new"来解决该问题,但是当然这不是多态的。
public new Child SomePropertyName
2.0中有什么解决方案吗?
3.5中解决此问题的任何功能如何?
解决方案
否。C不支持此想法(称为"返回类型协方差")。
但是,我们可以这样做:
public class FatherProp { } public class ChildProp: FatherProp { } public class Father { public virtual FatherProp SomePropertyName { get { return new FatherProp(); } } } public class Child : Father { public override FatherProp SomePropertyName { get { // override to return a derived type instead return new ChildProp(); } } }
即使用基类定义的合同,但返回派生类型。我做了一个更详细的示例,使这一点更加清楚,再次返回" this"不会改变任何内容。
可以(但很麻烦)测试返回的对象的实际类型(即"如果someObject是ChildProp"),但是最好在其上调用一个虚拟方法以对其类型执行正确的操作。
基类虚拟方法(在这种情况下为虚拟属性)不仅具有实现,而且还定义了契约:如果子类满足此契约,则子类可以提供SomePropertyName的不同实现(即SomePropertyName返回" FatherProp")。返回派生自" FatherProp"的" ChildProp"类型的对象符合此合同。但是我们不能在"儿童"中更改合同,该合同适用于"父亲"的所有后继类别。
如果我们退后一步,着眼于更广泛的设计,则Ctoolkit中还有其他语言构造,我们可能还想考虑泛型或者接口。
我们可以重新声明(新),但不能同时(使用相同的名称)重新声明和覆盖。
一种选择是使用受保护的方法来隐藏细节,从而允许同时进行多态和隐藏:
public class Father { public Father SomePropertyName { get { return SomePropertyImpl(); } } protected virtual Father SomePropertyImpl() { // base-class version } } public class Child : Father { public new Child SomePropertyName { get { // since we know our local SomePropertyImpl actually returns a Child return (Child)SomePropertyImpl(); } } protected override Father SomePropertyImpl() { // do something different, might return a Child // but typed as Father for the return } }
从维基百科:
In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding.
尽管它没有明确说明属性的协方差。
否,但是我们可以在2及更高版本中使用泛型:
public class MyClass<T> where T: Person { public virtual T SomePropertyName { get { return ...; } } }
然后父亲和孩子是同一类的通用版本
我们可以为父亲和孩子创建一个通用接口,并返回该接口的类型。
No. C# does not support this idea (it's called "return type covariance"). From Wikipedia: In the C# programming language, support for both return-type covariance and parameter contravariance for delegates was added in version 2.0 of the language. Neither covariance nor contravariance are supported for method overriding. You can re-declare (new), but you can't re-declare and override at the same time (with the same name). One option is to use a protected method to hide the detail - this allows both polymorphism and hiding at the same time:
最好的解决方案是使用泛型:
public class MyClass<T> where T: Person { public virtual T SomePropertyNameA { get { return ...; } } }//Then the Father and Child are generic versions of the same class
由于类型安全的考虑,在任何.NET语言中这都是不可能的。在类型安全的语言中,必须为返回值提供协方差,为参数提供协方差。采取以下代码:
class B { S Get(); Set(S); } class D : B { T Get(); Set(T); }
对于Get方法,协方差意味着T必须是S或者从S派生的类型。否则,如果对存储在类型为B的变量中的类型为D的对象的引用,则在调用B.Get()时将不会得到可表示为S的对象。类型系统。
对于Set
方法,矛盾性意味着T
必须是S
或者S
派生的类型。否则,如果引用了存储在类型为B的变量中的类型为D的对象,则在调用B.Set(X)时,其中X的类型为S而不是类型T,D :: Set(T)会得到一个不期望的类型的对象。
在C#中,有一个自觉的决定,即在属性重载时,即使它们只有一对getter / setter对,也不允许更改类型,因为否则它的行为会非常不一致("我们是说,我可以在一个带有吸气剂的吸尘器,而不是同时带有吸气剂和吸气剂的吸尘器?为什么不呢?!?"-匿名替代宇宙新手)。
这是到目前为止我能找到的最接近的:
public sealed class JustFather : Father<JustFather> {} public class Father<T> where T : Father<T> { public virtual T SomePropertyName { get { return (T) this; } } } public class Child : Father<Child> { public override Child SomePropertyName { get { return this; } } }
没有JustFather
类,除非它是其他派生类型,否则无法实例化Father <T>
。