约束泛型函数缺少扩展方法

时间:2015-10-28 14:10:48

标签: c# .net generics

我的问题代码是:

public void MyMethod<U, T>(U Array) where U : List<T>
{
  var sum = Array.Sum();
}

我得到的编译时错误是这样的:

  

错误CS1929&#39; U&#39;不包含&#39; Sum&#39;的定义最好的   扩展方法重载&#39; Queryable.Sum(IQueryable)&#39;需要一个   接收器类型&#39; IQueryable&#39;

这是Visual Studio 2015中的.NET Framework 4.6。这与此问题here类似,但我不确定相同的答案是否有效,因为编译器可以看到方法是明确约束。

有人可以给我一些指示,说明为什么会出现这个错误吗?

编辑:

示例代码可以进一步简化:

public void MyMethod<T>(List<T> myList)
{
  var sum = myList.Sum();
}

3 个答案:

答案 0 :(得分:2)

Sum的没有参数的重载是Sum的非泛型重载,其中IEnumerable已知为数字类型之一,例如:

public static int Sum(IEnumerable<int> source);
public static double Sum(IEnumerable<double> source);
//etc.

允许源序列为任何类型的泛型重载需要一个将项目输出为数值的选择器。

答案 1 :(得分:1)

要添加到Servy的优秀答案,您可以将选择器传递给Sum中使用的方法,如下所示:

public void MyMethod<T, U>(U items, Func<T, int> selector) where U : List<T>
{
    var sum = items.Sum(selector);
}

并称之为:

MyMethod<int, List<int>>(l, i => i);

答案 2 :(得分:1)

Servy的回答说 它必须是数字类型,但不是为什么,让我们检查一下。

给出以下功能模板:

public T SomeMethod<T>(List<T> items) where T : int { }

这很简单,泛型约束为特定类型,因此不需要是通用的(将T替换为int并且行为相同)。

现在让我们假设数字类型的类型系统有一个名为“NumericType”的公共基类:

public T SomeMethod<T>(List<T> items) where T : NumericType { }

这看起来与您可能想要的完全一样,但问题是什么,返回类型是什么?假设列表包含doubleintbyte等,每个类型在某些其他类型的乘法,添加,划分等时都有扩展转换,因此编译器很难说出什么返回类型应该是。

如果我们被允许做类似的事情,也会出现同样的问题:

public T SomeMethod<T>(List<T> items) where T : in(int, double, float) { }

int * int == int,但int * double == double,或更糟,{{1} } / double == int,正如您所看到的,int无法推断,这会破坏语言中的其他结构,例如:

T

由于var mySum = SomeMethod(myNumericList); 编译时隐式输入,因此无法确定适当的类型,因此无法编译该语句。

你能做的最好的事情是重载你的功能,所以你的原型变成了:

var

或者,另一方面,您可以坚持使用通用约束并执行以下操作:

public int SomeMethod(IEnumerable<int> items) { }
public double SomeMethod(IEnumerable<double> items) { }
public float SomeMethod(IEnumerable<float> items) { }

或者,正如DavidG的回答所指出的,使用选择器功能。