根据子类指定抽象方法在基类中的返回类型

19

以下是我的数据结构:

abstract class Base {
        public abstract List<...> Get(); //What should be the generic type?
}

class SubOne : Base {
    public override List<SubOne> Get() {

    }
}

class SubTwo : Base {
    public override List<SubTwo> Get() {

    }
}

我想创建一个抽象方法,该方法返回具体子类所属的任何类。因此,从示例中可以看出,SubOne 中的方法应返回 List<SubOne>,而 SubTwo 中的方法应返回 List<SubTwo>

在基类中声明的签名中,我应指定什么类型?


[更新]

感谢已发布的答案。

解决方案是使抽象类成为通用类,如下所示:

abstract class Base<T> {
        public abstract List<T> Get();
}

class SubOne : Base<SubOne> {
    public override List<SubOne> Get() {

    }
}

class SubTwo : Base<SubTwo> {
    public override List<SubTwo> Get() {

    }
} 

1
在您的更新/回答中,您将如何创建一个可以包含SubOne和SubTwo对象的“Base”类的列表或集合? - John Grabanski
5个回答

37

你的抽象类应该是泛型的。

abstract class Base<T> {
        public abstract List<T> Get(); 
}

class SubOne : Base<SubOne> {
    public override List<SubOne> Get() {

    }
}

class SubTwo : Base<SubTwo> {
    public override List<SubTwo> Get() {
    }
}
如果您需要引用不带泛型类型参数的抽象类,请使用接口:
interface IBase {
        //common functions
}

abstract class Base<T> : IBase {
        public abstract List<T> Get(); 
}

@recursive 您好,感谢您的回答 - 但是如何在使用接口的同时引用抽象类并调用 Get 方法呢? - BenKoshy
你会期望它返回什么类型?调用接口上的Get()似乎存在逻辑问题,因为列表元素类型是不同的。 - recursive
@递归 这是怎样的:abstract class Base{ public abstract List<T> Get<T>(); }是否只需要在方法自身之后,Get之后声明泛型类型,如此便可满足需求? --> Get<T> - Legends
@Legends:只有在为相同实例传递不同参数类型时才有意义调用Get()函数。但似乎这里并不是这种情况。 - recursive
我将上述实现更改为仅在方法级别上声明类型“T”,这迫使我对声明的返回类型“T”实施“where T:new()”约束。 当在类级别上声明类型“T”时,情况并非如此。 这显然是一个区别。 - Legends

4
public abstract class Base<T> 
{       
    public abstract List<T> Get(); 
}

class SubOne : Base<SubOne> 
{
    public override List<SubOne> Get() { return new List<SubOne>(); }
}

class SubTwo : Base<SubTwo> 
{
    public override List<SubTwo> Get() { return new List<SubTwo>(); }
}

2

试试这个:

public abstract class Base<T> {
  public abstract List<T> Foo();
}

public class Derived : Base<Derived> {   // Any derived class will now return a List of
  public List<Derived> Foo() { ... }     //   itself.
}

1

我认为你无法将其变为特定的子类。不过你可以这样做:

abstract class Base<SubClass> {
        public abstract List<SubClass> Get(); 
}
class SubOne : Base<SubOne> {
    public override List<SubOne> Get() {
        throw new NotImplementedException();
    }
}
class SubTwo : Base<SubTwo> {
    public override List<SubTwo> Get() {
        throw new NotImplementedException();
    }
}

0
如果您遇到一个情况,其中您的基类由于各种原因无法是泛型,那么这种方法可能会很有用:
abstract class Base {
}
interface IHasGetter<T> {
  List<T> Get();
}
static class HasGetterHelper {
    public static List<T> Get<T>(this T v) where T: IHasGetter<T>  => v.Get();
}
class SubOne : Base, IHasGetter<SubOne> {
    public List<SubOne> Get() {
        throw new NotImplementedException();
    }
}
class SubTwo : Base, IHasGetter<SubTwo> {
    public List<SubTwo> Get() {
        throw new NotImplementedException();
    }
}

如果您无法将接口添加到子类中,而且仍然无法将泛型添加到基础类型中,则可以使用此方法: (不幸的是,您无法将GetImpl设为protected,因为助手类不允许位于基类内部)

abstract class Base {
    public abstract List<T> GetImpl<T>() where T:Base;
}
static class HasGetterHelper {
    public static List<T> Get<T>(this T v) where T: Base => v.GetImpl<T>();
}
class SubOne : Base {
    public override List<T> GetImpl<T>() {
        throw new NotImplementedException();
    }
}
class SubTwo : Base {
    public override List<T> GetImpl<T>() {
        throw new NotImplementedException();
    }
}

在这两种情况下,这将按预期工作:
class Tester
{
   List<SubOne> TestIt() => new SubOne().Get();
}

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