一种返回派生类实例的抽象方法

Eri*_*ric 9 c# inheritance abstract-class

是否可以创建一个必须返回派生类实例的抽象方法?我可以做这个:

abstract class Base
{
   public abstract Base GetObj();
}

class Derived : Base
{
   public Derived() { }

   public override Base GetObj()
   {
       return new Derived();
   }
}
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有办法这样做,这Derived::GetObj()是被迫返回一个Derived

谢谢.

Luk*_*oid 20

使用泛型应该使这成为可能:

abstract class Base<T>
    where T : Base<T>
{
   public abstract T GetObj();
}

class Derived : Base <Derived>
{
   public Derived() { }

   public override Derived GetObj()
   {
       return new Derived();
   }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以进一步简化此操作(如果所有派生实例都是使用默认构造函数创建的):

abstract class Base<T>
    where T : Base<T>, new()
{
    public static T GetObj()
    {
        return new T();
    }
}

class Derived : Base<Derived>
{
    public Derived() { }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这只会强制*first*派生类返回自身.然后第二个派生类可以返回第一个. (3认同)

Ant*_*ram 7

你拥有的几乎,但不完全是一个抽象的工厂.我首先要说的是,您应该将它留给派生类的实现者来使它正确,或者只是相信它们会.

另一个答案显示了所谓的奇怪重复模板模式.在这里你有一个基类,它试图使用类型系统来强制派生类型在某些输入或输出位置使用它自己.

public abstract class Foo<T> where T : Foo<T>
public class Bar : Foo<Bar>
Run Code Online (Sandbox Code Playgroud)

这个想法可能适用于其他语言.只有人们正确使用它,它才能在C#中运行.有了Bar的上面定义,现在我也可以拥有

public class Baz : Foo<Bar> 
Run Code Online (Sandbox Code Playgroud)

这是完全合法的.Bar是一个Foo<Bar>,这是Baz使用它所需的全部.没有任何东西需要Baz实际使用Foo<Baz>.

C#中的类型系统根本无法强制执行您想要强制执行的操作.即使有这种模式,你仍然处于和以前一样的位置.您仍然必须信任派生类的实现者才能正确执行它.

有关此主题的更多信息,您可以阅读此博客.