如何在C#中重写子类的重写方法中的子类型?

时间:2009-01-07 20:01:34

标签: c# inheritance

我有一个带有over-ridden方法的子类,我知道它总是返回基类中声明的返回类型的特定子类型。如果我以这种方式编写代码,它将无法编译。由于这可能没有意义,让我举一个代码示例:

class BaseReturnType { }
class DerivedReturnType : BaseReturnType { }

abstract class BaseClass {
    public abstract BaseReturnType PolymorphicMethod();
}

class DerivedClass : BaseClass {
    // Compile Error: return type must be 'BaseReturnType' to match 
    // overridden member 'BaseClass.PolymorphicMethod()'
    public override DerivedReturnType PolymorphicMethod() { 
        return new DerivedReturnType(); 
    }
}

有没有办法在C#中实现这一目标?如果没有,那么实现类似目标的最佳方式是什么?为什么不允许这样做?它似乎不允许任何逻辑不一致,因为从over-ridden方法返回的任何对象仍然是is BaseReturnType。也许有些东西我没考虑过。或者可能是技术或历史原因。

7 个答案:

答案 0 :(得分:18)

不幸的是,C#中不支持协变返回类型以进行方法重写。 (Ditto contravariant参数类型。)

如果您正在实施一个界面,您可以使用“弱”版本明确地实现它,并提供具有更强合同的公共版本。对于父类的简单覆盖,你恐怕没有这种奢侈:(

(编辑:Marc有一个reasonable solution - 虽然它非常丑陋,隐藏方法通常对可读性不利。没有冒犯意味着,Marc;)

相信这实际上是一种CLR限制,而不仅仅是语言限制 - 但我可能错了。

(作为历史问题,Java(该语言)在1.5之前具有相同的限制 - 但它与泛型同时获得了协方差。)

答案 1 :(得分:17)

如果不困扰你,你可以使这个类变得通用:

    class BaseReturnType { }
    class DerivedReturnType : BaseReturnType { }

    abstract class BaseClass<T> where T : BaseReturnType
    {
        public abstract T PolymorphicMethod();
    }

    class DerivedClass : BaseClass<DerivedReturnType>
    {
        // Error: return type must be 'BaseReturnType' to match 
        // overridden member 'BaseClass.PolymorphicMethod()'
        public override DerivedReturnType PolymorphicMethod()
        {
            return new DerivedReturnType();
        }
    }

答案 2 :(得分:12)

如果你引入一个额外的方法来覆盖(因为你不能overridenew同一类型的同名方法),你可以这样做:

abstract class BaseClass
{
    public BaseReturnType PolymorphicMethod()
    { return PolymorphicMethodCore();}

    protected abstract BaseReturnType PolymorphicMethodCore();
}

class DerivedClass : BaseClass
{
    protected override BaseReturnType PolymorphicMethodCore()
    { return PolymorphicMethod(); }

    public new DerivedReturnType PolymorphicMethod()
    { return new DerivedReturnType(); }
}

现在,每个级别的PolymorphicMethod方法都有正确的类型。

答案 3 :(得分:2)

泛型不一定是要走的路。特别是,(Derived)类型不被认为是(Base)类型。

首先,向派生类添加一个新方法,该方法将返回具有正确类型的值。其次,将覆盖方法标记为不可覆盖,并将其委托给新方法。

就是这样。你已经解决了问题。子类将无法重新扩展类型,因为它们必须覆盖您的新方法。

如果代码不对,我道歉;我习惯了VB.net。

abstract class C1 {
    public abstract IEnumerable<Byte> F1();
}
class C2 : C1 {
    public sealed override IEnumerable<Byte> F1() {
        Return F2();
    }
    public overridable IList<Byte> F2() {
        Return {1, 2, 3, 4};
    }
}

答案 4 :(得分:1)

class BaseReturnType { }
class DerivedReturnType : BaseReturnType { }

abstract class BaseClass {
    public abstract BaseReturnType PolymorphicMethod();
}

class DerivedClass : BaseClass {
    // Error: return type must be 'BaseReturnType' to match 
    // overridden member 'BaseClass.PolymorphicMethod()'
    public override BaseReturnType PolymorphicMethod() { 
        return new DerivedReturnType(); 
    }
}

这应该有效

答案 5 :(得分:1)

将Derived类上的方法签名更改为:

 public override BaseReturnType PolymorphicMethod() 
 {
    return new DerivedReturnType();     
 }

C#不支持变量返回类型。您可以查看此帖子,了解使用Generics ... http://srtsolutions.com/blogs/billwagner/archive/2005/06/17/covaraint-return-types-in-c.aspx

执行此操作的方法

以下是模型中使用Generics的示例:

public class BaseReturnType
{
}
public class DerivedReturnType : BaseReturnType
{
}

public abstract class BaseClass<T> where T : BaseReturnType
{
    public abstract T PolymorphicMethod();

}

public class DerviedClass : BaseClass<DerivedReturnType>
{
    public override DerivedReturnType PolymorphicMethod()
    {
        throw new NotImplementedException();
    }
}

答案 6 :(得分:0)

在我看来,你需要返回一个接口,而不是基类。