如何在 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
How to return subtype in overridden method of subclass in C#?
提问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 override
and new
a method with the same name in the same type):
如果你引入一个额外的方法来覆盖,你可以这样做(因为你不能override
和new
一个相同类型的同名方法):
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 PolymorphicMethod
method 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};
}
}