将静态方法的返回类型约束为当前类类型



我在基类中有一个类层次结构和一个静态方法,所以子类也有这个静态方法。我想定义一个像

这样的静态方法
public static IEnumerable<T> GetList<T>()
    where T : BaseClass, new()
{
    return new List<T>() { ... };
}

所以我可以调用

var list = ChildClass.GetList();

和list将是IEnumerable<ChildClass>。但是:我不知道如何告诉编译器将泛型类型推断为我调用的类的类型,所以这种用法会产生错误,我必须将其纠正为冗余的

var list = ChildClass.GetList<ChildClass>();

我可以使用扩展方法(它们有this参数,允许编译器抓住),但我想在没有ChildClass实例化的情况下这样做。

有没有一种方法可以不重复地完成这个任务?

你不能让编译器推断出你调用的类,因为从技术上讲,你总是从定义方法的类中调用。

编译器允许您使用派生类名来代替,这只是为了方便。

如果您可以忍受难看的hack,您可以使BaseClass本身泛型,并将子类的类型作为参数传递给泛型参数,如:

class BaseClass<T> where T : BaseClass<T>, new()
{
    public static IEnumerable<T> GetList()
    {
        return new List<T>() { new T() }; // whatever
    }
}
class Child : BaseClass<Child>
{
}
class Child2 : BaseClass<Child2>
{
}

现在Child.GetList()返回一个IEnumerable<Child>, Child2.GetList()返回一个IEnumerable<Child2>

如果你想知道为什么编译器不能解析类型,请继续阅读:

首先,静态方法绑定到类型而不是对象。所以这里不可能有任何多态行为。所以事实上,你有一个子类,基类层次结构在这里并不重要,因为方法绑定到两个完全不同的实体。

真正的问题在于c#编译器的类型推断能力。您必须向编译器提供有关T类型的一些信息。否则它不能推断它。

你也不能在左边给出这个信息,因为c#的类型推断是从右到左的。换句话说:

var ints = new {};

很好。因为右边的类型是一个匿名方法,而int被解析为一个。但是:

int[] ints = new [] {};

不会工作。编译器报错"没有为隐式类型数组找到最佳类型"。换句话说,编译器不能使用左边的信息来确定右边的类型应该是什么。

在你的问题

var list = ChildClass.GetList();

没有给编译器任何关于T是什么的信息!即使您使用的是类型而不是var,也不会有什么不同。

最新更新