2012-03-17 30 views
2

我需要爲List(T)編寫一個通用擴展方法,該方法有條件地考慮T的每個字符串屬性,然後在滿足條件時將T的相應小數屬性相加。我的努力迄今:擴展方法,SumIf通用列表<T>

// foreach(p in Persons) { if(p.Name == "mort"){sum p.Amount;} } 

public static double SumIf<T>(this T o, List<T> ListItems, 
      string targetStr, ?strVals?, ?dblVals?) 
{ 
    double sum = 0; 
    foreach(T item in ListItems) 
    { 
     if(item.?strVal? == targetStr){ sum += item.?dblVal? ; } 
    } 
    return sum; 
} 

感謝您的任何指導, 莫特

+0

沒有上面的方法給你什麼問題? – 2012-03-17 23:01:01

+0

['Aggregate'](http://msdn.microsoft.com/library/system.linq.enumerable.aggregate.aspx)不適合你嗎?或['Where'](http://msdn.microsoft.com/library/system.linq.enumerable.where.aspx)後跟['Sum'](http://msdn.microsoft.com/library/system .linq.enumerable.sum.aspx)?或者你想要一個助手擴展方法? – BACON 2012-03-17 23:02:36

回答

4

這聽起來像你想提取字符串屬性和雙重屬性的一種方式(假設「十進制」在您的文章是一個錯字,而不是在你的代碼「雙」) - Func是合適的位置:

public static double SumIf<T>(this IEnumerable<T> source, 
      string targetText, 
      Func<T, string> textSelector, 
      Func<T, double> valueSelector) 
{ 
    double sum = 0; 
    foreach (T item in source) 
    { 
     if (textSelector(item) == targetText) 
     { 
      sum += valueSelector(item); 
     } 
    } 
    return sum; 
} 

(請注意,我已經刪除未使用的初始參數,並使其列表本身上的擴展方法不使用。價值感覺像ab它一聞到我的......我也改變了參數類型IEnumerable<T>因爲你不需要它是一個真正的列表)

注意,這實際上大多等同於:

public static double SumIf<T>(this IEnumerable<T> source, 
      string targetText, 
      Func<T, string> textSelector, 
      Func<T, double> valueSelector) 
{ 
    return source.Where(x => textSelector(x) == targetText) 
       .Sum(valueSelector); 
} 

我個人可能去一個一般謂詞函數而不是字符串和文本選擇:

public static double SumIf<T>(this IEnumerable<T> source, 
      Func<T, bool> predicate, 
      Func<T, double> valueSelector) 
{ 
    return source.Where(predicate) 
       .Sum(valueSelector); 
} 

然後你會跟

double sum = list.SumIf(x => x.Name == "mort", x => x.Amount); 
叫它

...這似乎只是作爲對我好爲:

double sum = list.SumIf("mort", x => x.Name, x => x.Amount); 

...但明顯更靈活。

正如評論中指出的,你真的需要這個嗎?您是否在足夠的地方使用它以使簡單的Where/Sum調用無法忍受?

double sum = list.Sum(x => x.Name == "mort" ? x => x.Amount : 0d); 
+0

一切都很好,除了在第二個實現中調用Select並將列表類型更改爲字符串,因此您無法爲T列表調用Sum。 – 000 2012-03-17 23:22:35

+0

@Sam:確實,謝謝。 – 2012-03-17 23:24:37

+0

謝謝你糾正它 – 000 2012-03-17 23:25:41

0

你介紹給你的方法一些非常具體的限制,使得它,它不能通用,例如:哎呀,你可以使用條件運算符將它逼到了Sum電話T必須有財產金額。這是更好地傳遞這些依賴關係作爲功能:

public static double SumIf<T>(this IList<T> source, 
           Func<T, bool> pred, 
           Func<T, double> val) 
{ 
    double sum = 0; 
    foreach (var item in source) 
     if (pred(item)) 
      sum += val(item); 

    return sum; 
} 

然後,你可以在你的謂語和財產選擇作爲傳遞lambda表達式:

List<Person> people = new List<Person>(); 
people.Add(new Person() { Name = "Joe", Amount =20.2}); 
people.Add(new Person() { Name = "Fred", Amount = 11 }); 
people.Add(new Person() { Name = "Joe", Amount = 5.7 }); 

double sum = people.SumIf(x => x.Name == "Joe", x => x.Amount);