簡體   English   中英

C# 創建一個包含泛型集合的泛型方法並調用 Sum()

[英]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是否是這些類型之一。

注意longInt64相同, intInt32相同, singlefloat相同。

您可以借助委托提供某種聚合功能:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM