我有一个带有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
。也许有些东西我没考虑过。或者可能是技术或历史原因。
答案 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)
如果你引入一个额外的方法来覆盖(因为你不能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(); }
}
现在,每个级别的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)
在我看来,你需要返回一个接口,而不是基类。