从父类方法返回子类的返回类型

9
如果我有一个类A,以及继承自A的类B、C和D,是否有一种方法可以在A中编写一个方法,当在子类上调用该方法时,返回类型是子类?
因此,如果我执行A.myMethod(),我会得到一个A,如果我执行B.myMethod(),我会得到一个B的实例?

我认为你基本上是在谈论构造函数;你只是想要稍微不同的命名方式。对吗? - adv12
@adv12 对我来说更像是一个稍微有些混乱的工厂。 - BradleyDotNET
5个回答

5
你所要求的并不是严格意义上的多态,因为你想要覆盖返回类型,这样会使得方法的签名与原始方法不同。真正的多态不会改变方法的签名,所以你所要求的在C#中并不是一种一流的情况。
话虽如此,至少有两种方法可以实现你的需求。
最简单的方法是覆盖该方法,并使用 "new" 关键字隐藏原始方法,从而允许你更改签名。
public new B MyMethod() { return (B)(base.MyMethod()); }

这将允许任何对B的使用都返回一个B,但实际上并没有覆盖A.MyMethod的行为。在代码中避免重复类型转换非常有用。
如果您需要还要重写方法以允许它返回一个B类型对象,则无法在同一类中共存,因为编译器看到相同的签名(相同的名称、相同的参数,即使返回类型是明确不同的)。
第二种方式被称为静态多态性(Static Polymorphism),如果您正在使用某种工厂,这非常有用,但却很棘手,因为它仅允许一级实际继承。静态多态类型始于具有针对自身约束的通用组件的类型:
public class A<TSelf> where TSelf : A<TSelf> { }
public class B : A<B> { }

这意味着您的方法可以返回类型为TSelf的对象,甚至可以将其设置为抽象方法,以便每个继承者都必须处理构造函数。但是,任何从B继承的类在重写此方法时会更加困难,因为它继承自A<B>,而不是A<C>

0
假设您想要在仅 A 中声明方法 myMethod,您可以执行以下操作:
namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new A();
            var b = new B();

            Console.WriteLine(a.M());
            Console.WriteLine(b.M());
        }
    }

    class A
    {
        public A M()
        {
            return (A)Activator.CreateInstance(GetType());
        }
    }

    class B : A 
    {
    }
}

输出:

Test.A
Test.B 

方法隐藏=不好。至少要明确它。如果您尝试通过多态调用M,则这将无法正常工作。 - BradleyDotNET
@BradleyDotNET 当然,但无论它是好是坏,这就是所要求的。 - ie.
我同意,除了原帖的作者可能试图以多态的方式实现这一点(很难确定)。 - BradleyDotNET
@BradleyDotNET,哦,我明白了,看起来OP根本不想在B、C、D中覆盖(定义)方法,只想在A中这样做。 - ie.

0
你所说的基本上是工厂方法/模式。有点不太一样,因为实例自己创建起来有些奇怪。
但是没问题,你可以这么写:
class A
{
   public virtual A Create()
   {
      return new A();
   }
}

class B
{
   public override A Create()
   {
       return new B();
   }
}

当然,返回类型必须保持为基类,但由于您正在利用多态性,这不应该是问题。

通常工厂方法会在另一个专门的类中,这样您就知道了。


0

是和不是。考虑一下:

public class Parent
    {
        public int MyProperty { get; set; }

        public virtual Parent MyMethod()
        {
            return new Parent();
        }
    }

    public class A : Parent
    {
        public override Parent MyMethod()
        {
            return new A();
        }
    }

在A中,尽管返回类型为Parent,但你却返回了一个A。

0

如果你在问编译时,不,你不能编写具有不同返回类型的覆盖方法。

但是在运行时,是的,你可以,并且你将拥有这些类型的实例,但你必须编写你的代码以使其具有返回类型“ A”,然后将它们转换为所需的类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接