我在基类中有一个类层次结构和一个静态方法,所以子类也有这个静态方法。我想定义一个像
这样的静态方法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,也不会有什么不同。