我重载了如下所示的通用方法:
public static T DoSomething<T>(T val)
{
return val;
}
public static IEnumerable<T> DoSomething<T>(IEnumerable<T> vals)
{
return vals.Select(x => DoSomething(x));
}
我遇到的问题是以下代码无法编译:
var myList = new List<SomeObject>();
// This will not compile
PropertyOfTypeIEnumerable_SomeObject = MyStaticClass.DoSomething(myList);
编译器抱怨无法将SomeObject
转换为IEnumerable<SomeObject>
。这表明编译器正在选择DoSomething的第一个版本,该版本采用通用类型T,而第二个版本则采用限制性更强的通用类型IEnumerable。
我可以通过将第二个重载方法重命名为DoSomethingList并显式调用该名称来确认是这种情况:
public static T DoSomething<T>(T val)
{
return val;
}
public static IEnumerable<T> DoSomethingList<T>(IEnumerable<T> vals)
{
return vals.Select(x => DoSomething(x));
}
// ...
var myList = new List<SomeObject>();
// This compiles ok
PropertyOfTypeIEnumerable_SomeObject = MyStaticClass.DoSomethingList(myList);
我的问题是,为什么编译器不选择限制性最强的匹配泛型实现来调用,并且有什么方法可以使这种行为而不必唯一地命名和显式调用呢?如果该示例为彼此继承的不同对象调用重载,则它将根据声明的变量类型选择限制性最强的重载。为什么它也不对泛型也这样做?
另一种选择是不重载方法,而是检查DoSomething方法内部以查看T是否可从IEnumerable <>赋值,但后来我不知道如何将其实际转换为我可以称之为的启用Linq方法,并且我不知道如何使编译器正常返回该Linq方法的结果,因为 I 将知道返回结果必须是IEnumerable,但是< em> compiler 不会。
答案 0 :(得分:1)
C#中的泛型与C ++模板(1)有很多不同。如果我们在进行C ++元编程,它将调用更具限制性的IEnumerable<T>
函数,这是对的。但是,在C#中,<T>
函数与List<T>
的匹配更好,因为它更精确。
我已经在上面测试了您的代码,并且它在.NET v4.0.30319上对我来说编译就很好,但是它返回List<T>
类型,而不是Select调用返回的预期的简化IEnumerable<T>
类型。表示已调用<T>
函数。
如果要对DoSomething
扩展类中的所有对象执行IEnumerable
,则可以采用以下方法:
public static T DoSomething<T>(T val)
{
switch (val)
{
case IEnumerable vals:
foreach (object x in vals)
DoSomething(x);
break;
}
return val;
}
我将其设置为允许匹配其他特定类型,因为我猜每种不同的类型都会做不同的事情。如果不希望这样做,您始终可以只使用简单的if...is
语句匹配。