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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/421851/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 02:48:20  来源:igfitidea点击:

How to return subtype in overridden method of subclass in C#?

c#inheritance

提问by recursive

I have a subclass with an over-ridden method that I know always returns a particular subtype of the return type declared in the base class. If I write the code this way, it won't compile. Since that probably doesn't make sense, let me give a code example:

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

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

Is there any way to accomplish this in C#? If not, what's the best way to achieve something similar? And why isn't it allowed? It doesn't seem to allow any logical inconsistency, since any object returned from the over-ridden method still is BaseReturnType. Maybe there is something I hadn't considered though. Or maybe the reason is technological or historical.

有什么办法可以在 C# 中实现这一点吗?如果没有,实现类似目标的最佳方法是什么?为什么不允许?它似乎不允许任何逻辑不一致,因为从重写的方法返回的任何对象仍然is BaseReturnType. 也许有一些事情我没有考虑过。或者可能是技术或历史原因。

采纳答案by Jon Skeet

Unfortunately no, covariant return types aren't supported in C# for method overriding. (Ditto contravariant parameter types.)

不幸的是,C# 中不支持协变返回类型进行方法覆盖。(同上逆变参数类型。)

If you're implementing an interface you can implement it explicitly with the "weak" version and also provide a public version with the stronger contract. For simple overriding of a parent class, you don't have this luxury I'm afraid :(

如果您正在实现一个接口,您可以使用“弱”版本显式实现它,并提供具有更强合约的公共版本。对于父类的简单覆盖,恐怕您没有这种奢侈:(

(EDIT: Marc has a reasonable solution- although it's pretty ugly, and method hiding is generally a bad thing for readability. No offence meant, Marc ;)

(编辑:Marc 有一个合理的解决方案- 尽管它很丑陋,并且方法隐藏通常对可读性来说是一件坏事。没有冒犯的意思,Marc ;)

I believethis is actually a CLR restriction, not just a language one - but I could well be wrong.

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

(As a matter of history, Java (the language) had the same restriction until 1.5 - but it gained covariance at the same time as generics.)

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

回答by Greg Hurlman

It seems to me that you need to be returning an interface, not a base class.

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

回答by anand

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

this should work

这应该有效

回答by Marc Gravell

You can do this if you introduce an extra method to override (since you can't overrideand newa method with the same name in the same type):

如果你引入一个额外的方法来覆盖,你可以这样做(因为你不能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(); }
}

Now you have a PolymorphicMethodmethod at each level with the correct type.

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

回答by Stormenet

You could make the class generic if that doesn't bothers you:

如果这不打扰您,您可以使类通用:

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

回答by JoshBerke

Change your method signature on Derived class to:

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

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

C# doesn't support variant return types. You can check out this post for a way to do this using Generics...http://srtsolutions.com/blogs/billwagner/archive/2005/06/17/covaraint-return-types-in-c.aspx

C# 不支持变体返回类型。您可以查看这篇文章,了解使用泛型来实现此目的的方法... http://srtsolutions.com/blogs/billwagner/archive/2005/06/17/covarint-return-types-in-c.aspx

Here's a sample using Generics in your model:

这是在您的模型中使用泛型的示例:

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

回答by Craig Gidney

Generics are not necessarily the way to go. In particular, type(of Derived) is not considered a type(of Base).

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

First, add a new method to your derived class which will return the value with the correct type. Second, mark the overriding method not-overridable and have it delegate to your new method.

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

That's it. You've solved your problem. Child classes won't be able to re-expand the type because they must override your new method.

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

I apologize if the code isn't quite right; I'm used to VB.net.

如果代码不太正确,我深表歉意;我习惯了 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};
    }
}