[英]C# Create a Generic method contains generic collection and invoke Sum()
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Fun<T>(List<T> list)
{
// The foreach works
foreach(T i in list)
{
Console.WriteLine(i);
}
//The following line has error: List<T>' does not contain a definition for 'Sum'
Console.WriteLine(list.Sum());
}
public static void Main()
{
var arr = new int[]{1,2,3,4};
Fun<int>(arr.ToList());
}
}
the foreach
works, but list.Sum()
doesn't. foreach
有效,但list.Sum()
无效。 It shows:表明:
'List' does not contain a definition for 'Sum' and the best extension method overload 'Queryable.Sum(IQueryable)' requires a receiver of type 'IQueryable'
“List”不包含“Sum”的定义,并且最佳扩展方法重载“Queryable.Sum(IQueryable)”需要“IQueryable”类型的接收器
if I declare as public static void Fun(List<int> list)
, then it works, anybody know why?如果我声明为
public static void Fun(List<int> list)
,那么它可以工作,有人知道为什么吗?
a similar C++ version can work:类似的 C++ 版本可以工作:
#include <iostream>
#include <vector>
using namespace std;
template<class T>
struct MyList
{
MyList(vector<T> v) : m(v){};
vector<T> m;
T Sum()
{
T sum = T();
for(auto i : m)
{
sum += i;
}
return sum;
}
};
template<class T>
void Fun(MyList<T> list)
{
cout << list.Sum() << endl;
}
int main(int argc, char *argv[])
{
Fun(MyList<int>({1,2,3}));
Fun(MyList<double>({1.0,2.0,3.0}));
}
output:
6
6.3
The difference between your C++ code and C# code is that in your C++ code, your MyList<T>
template explicitly defines a Sum
method.您的 C++ 代码和 C# 代码之间的区别在于,在您的 C++ 代码中,您的 MyList
MyList<T>
模板明确定义了Sum
方法。 In contrast, C#'s List<T>
doesn't define a Sum()
method.相反,C# 的
List<T>
没有定义Sum()
方法。 Rather, List<T>
implements IEnumerable<T>
, and there are extension methods in the System.Linq
namespace to provide Sum
functionality to certain closed types of IEnumerable<T>
.相反,
List<T>
实现IEnumerable<T>
,并且在System.Linq
命名空间中有扩展方法为某些封闭类型的IEnumerable<T>
提供Sum
功能。
Referring to the documentation , you'll see that Sum
(without a selector, so not something like Sum(x => x.Value)
) is only defined for the following closed types:参考文档,您会看到
Sum
(没有选择器,所以不是Sum(x => x.Value)
类的东西)仅针对以下封闭类型定义:
IEnumerable<Single>
IEnumerable<Int32>
IEnumerable<Int64>
IEnumerable<Double>
IEnumerable<Decimal>
IEnumerable<Nullable<Single>>
IEnumerable<Nullable<Int32>>
IEnumerable<Nullable<Int64>>
IEnumerable<Nullable<Double>>
IEnumerable<Nullable<Decimal>>
Therefore, it is not a feature of List<T>
, and there is now way for the compiler to verify at compile time that the T
in List<T>
will be one of these types.因此,它不是
List<T>
的一个特性,现在编译器可以在编译时验证List<T>
中的T
是否是这些类型之一。
Note that long
is the same as Int64
, int
is the same as Int32
, and single
is the same as float
.注意
long
与Int64
相同, int
与Int32
相同, single
与float
相同。
You could possibly provide some kind of aggregation functionality with the aid of a delegate:您可以借助委托提供某种聚合功能:
public static void Fun<T>(List<T> list, Func<T, T, T> sumDelegate)
{
T sumValue = default(T);
// The foreach works
foreach(T i in list)
{
Console.WriteLine(i);
sumValue = sumDelegate(sumValue, i);
}
//The following line has error: List<T>' does not contain a definition for 'Sum'
Console.WriteLine(sumValue);
}
And then call it like so:然后这样称呼它:
var arr = new int[]{1,2,3,4};
Fun<int>(arr.ToList(), (x, y) => x + y);
I don't know, how C++ works in this case, but in your code generic type parameter T
isn't constrained to any type and compiler doesn't know whether T
supports +
operator or not.我不知道 C++ 在这种情况下如何工作,但是在您的代码中,泛型类型参数
T
不受任何类型的限制,编译器不知道T
是否支持+
运算符。 You can use dynamic
keyword here to allow the compiler to determine the type in runtime您可以在此处使用
dynamic
关键字以允许编译器在运行时确定类型
public static void Fun<T>(List<T> list)
{
dynamic sum = default(T);
foreach (T i in list)
{
Console.WriteLine(i);
sum += (dynamic)i;
}
Console.WriteLine(sum);
}
Or just in one line var sum = list.Aggregate((arg1, arg2) => (dynamic)arg1 + arg2);
或者只是在一行
var sum = list.Aggregate((arg1, arg2) => (dynamic)arg1 + arg2);
But you should be very careful with it.但是你应该非常小心。 If you pass a type, which doesn't support or overload the
+
, you'll get an exception in runtime.如果您传递一个不支持或重载
+
的类型,您将在运行时遇到异常。 You can apply generic constraint to T
and allow it match only numeric types where T: struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
(it's quite long, but there is no generic constraint to match a numeric types in C# for now)您可以将泛型约束应用于
T
并允许它仅匹配where T: struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
(它很长,但没有泛型约束来匹配数字类型在 C# 中)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.