![](/img/trans.png)
[英]Invoke a generic method with generic arguments defined in a generic class in C#
[英]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());
}
}
foreach
有效,但list.Sum()
無效。 表明:
“List”不包含“Sum”的定義,並且最佳擴展方法重載“Queryable.Sum(IQueryable)”需要“IQueryable”類型的接收器
如果我聲明為public static void Fun(List<int> list)
,那么它可以工作,有人知道為什么嗎?
類似的 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
您的 C++ 代碼和 C# 代碼之間的區別在於,在您的 C++ 代碼中,您的 MyList MyList<T>
模板明確定義了Sum
方法。 相反,C# 的List<T>
沒有定義Sum()
方法。 相反, List<T>
實現IEnumerable<T>
,並且在System.Linq
命名空間中有擴展方法為某些封閉類型的IEnumerable<T>
提供Sum
功能。
參考文檔,您會看到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>>
因此,它不是List<T>
的一個特性,現在編譯器可以在編譯時驗證List<T>
中的T
是否是這些類型之一。
注意long
與Int64
相同, int
與Int32
相同, single
與float
相同。
您可以借助委托提供某種聚合功能:
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);
}
然后這樣稱呼它:
var arr = new int[]{1,2,3,4};
Fun<int>(arr.ToList(), (x, y) => x + y);
我不知道 C++ 在這種情況下如何工作,但是在您的代碼中,泛型類型參數T
不受任何類型的限制,編譯器不知道T
是否支持+
運算符。 您可以在此處使用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);
}
或者只是在一行var sum = list.Aggregate((arg1, arg2) => (dynamic)arg1 + arg2);
但是你應該非常小心。 如果您傳遞一個不支持或重載+
的類型,您將在運行時遇到異常。 您可以將泛型約束應用於T
並允許它僅匹配where T: struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
(它很長,但沒有泛型約束來匹配數字類型在 C# 中)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.