我可以覆盖派生类型吗?

时间:2020-03-06 14:58:17  来源:igfitidea点击:

据我所知,不可能在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 &lt;T>