据我所知,无法在C#2.0中执行以下操作

public class Father
{
    public virtual Father SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

public class Child : Father
{
    public override Child SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

我通过在派生类中创建<!> quot; new <!> quot;来解决问题,但当然这不是多态的。

public new Child SomePropertyName

2.0中有什么解决方案吗? 3.5中解决此问题的任何功能如何?

有帮助吗?

解决方案

由于类型安全问题,这在任何.NET语言中都是不可能的。在类型安全的语言中,您必须为返回值和参数的逆变提供协方差。拿这个代码:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

对于Get方法,协方差意味着T必须是S或从D派生的类型。否则,如果您对类型为B的对象的引用存储在变量类型B.Get()中,则当您调用Set时,您将无法获得可表示为B.Set(X)的对象,从而破坏类型系统

对于X方法,逆变意味着D::Set(T)必须是<=>或<=>派生自的类型。否则,如果您对类型为<=>的对象的引用存储在变量类型<=>中,则当您调用<=>时,其中<=>的类型为<=>但不是类型<=>,< =>会得到一个它没想到的类型的对象。

在C#中,有意识地决定在重载属性时不允许更改类型,即使它们只有一个getter / setter对,因为它会有非常不一致的行为( <!> quot;你的意思是,我可以用一个getter改变一个类型,但不能同时改变getter和setter的类型?为什么不呢?!?<!> - Anonymous Alternate Universe Newbie)。

其他提示

您可以重新声明(新),但不能同时重新声明和覆盖(使用相同的名称)。 一种选择是使用受保护的方法来隐藏细节 - 这允许同时进行多态和隐藏:

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
    }
}

不,但您可以在2及以上版本中使用泛型:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

然后父亲和孩子是同一类的通用版本

来自维基百科

  

在C#编程语言中,支持return-type   协方差和参数   增加了代表们的逆转   在该语言的2.0版本中。   既不是协方差也不是逆变   支持方法覆盖。

虽然没有明确说明属性的协方差。

您可以为父子创建一个公共接口,并返回该接口的类型。

没有。 C#不支持这个想法(它被称为<!> quot; return type covariance <!> quot;)。 但是你可以这样做:

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();
        }
    }
}

即。使用基类定义的契约,但返回派生类型。我已经做了一个更详细的例子来使这一点更加清晰 - 返回<!>“这个<!>”;再也不会改变任何事情。

可能(但是很乱)测试返回的对象的实际类型(即<!> quot;如果someObject是ChildProp <!>“;),但最好在它上面调用一个虚拟方法正确的类型。

基类虚方法(在本例中为虚拟属性)不仅具有实现,还定义了一个契约:如果子类符合此契约,则子类可以提供SomePropertyName的不同实现(即SomePropertyName返回一个对象)类型<!>“; FatherProp <!>”;)。返回类型<!>的对象;“ChildProp <!>”;派生自<!>“; FatherProp <!>”;符合这份合同。但你无法在<!>中改变合约; Child <!> - 此合同适用于所有来自<!> quot;父<!>;。

的类

如果您退后一步并查看更广泛的设计,C#工具箱中还有其他语言结构,您可能还需要考虑这些结构 - 泛型或接口。

  

没有。 C#不支持这个想法   (它被称为<!> quot;返回类型   协方差QUOT <!>;)

     

来自维基百科:

     

在C#编程语言中,   支持返回类型   协方差和参数   增加了代表们的逆转   在该语言的2.0版本中。   既不是协方差也不是逆变   支持方法覆盖。

     

你可以重新声明(新),但是你   无法重新声明和覆盖   同一时间(同名)。一   选项是使用受保护的方法   隐藏细节 - 这允许两者   多态性和隐藏在同一个   时间:

最好的解决方案是使用泛型:

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

这是我能来的最近的(到目前为止):

    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>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top