Return 来自父 class 方法的子 class 类型

Return type of child class from parent class method

如果我有 class A 和 class 继承自 [=] 的 BCD 13=],有没有办法在 A 中编写一个方法,当在 subclass 上调用时,将具有 subclass 的 return 类型?

所以如果我要执行 A.myMethod(),我会得到一个 A,如果我要执行 B.myMethod(),我会得到一个 B 的实例?

假设你只想在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 

你说的是基本上一个工厂method/pattern。有点不对劲,因为创建自己的实例很奇怪。

但是当然,你可以这样写:

class A
{
   public virtual A Create()
   {
      return new A();
   }
}

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

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

通常情况下,工厂方法会在 另一个 专门构建的 class 中,如你所知。

是和否。考虑:

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 中,虽然 return 类型是 Parent,但您 return 是一个 A。

如果你询问编译时间,不,你不能用不同的 return 类型编写重写方法。

但是在 运行 时间是的,你可以并且你将拥有那些类型的实例,但是你必须编写代码以获得 return 类型的 'A' 然后将它们转换为想要的类型。

你问的不是严格的多态性,因为你想覆盖 return 类型,因此具有与原始方法不同的签名。真正的多态性改变了这个签名的 none,所以你问的不是 C# 中的第一个 class 情况。

话虽如此,至少有两种方法。

最简单的方法是覆盖方法,使用new关键字隐藏原来的方法,让你改变签名。

public new B MyMethod() { return (B)(base.MyMethod()); }

这将允许 B 到 return 和 B 的任何用法,但实际上不会覆盖 A.MyMethod 的行为。避免在代码中重复类型转换很有用。

如果您还需要重写该方法以允许它 return 类型为 B 的对象,这不能共存于同一个 class,因为编译器认为相同签名(相同的名称,相同的参数,即使 return 类型明显不同)。

第二种方法称为静态多态性,如果您使用某种工厂,它会非常有用,但变通起来可能非常棘手,因为它允许一级实际继承。静态多态类型以具有针对自身约束的通用组件的类型开始:

public class A<TSelf> where TSelf : A<TSelf> { }
public class B : A<B> { }

这意味着您的方法可以 return 类型为 TSelf 的对象,甚至可以将其设为抽象方法,因此每个继承者都必须处理构造函数,但是任何 class 继承自B 更难覆盖它,因为它继承自 A<B>,而不是 A<C>