2010-08-17 75 views
2

我有兩種方法看起來幾乎相同,除了在Linq查詢中使用的集合函數外。例如:集合函數與linq之間切換

public IEnumerable<Item> DoStuff(IEnumerable<Item> someItems) { 
    var items = someItems.GroupBy(i => i.Date).Select(p => new Item(p.Key, p.Sum(r => r.Value))); 
    // ... 
} 

public IEnumerable<Item> DoOtherStuff(IEnumerable<Item> someItems) { 
    var items = someItems.GroupBy(i => i.Date).Select(p => new Item(p.Key, p.Max(r => r.Value))); 
    // ... 
} 

其中Item是這樣一類:

public class Item { 
    public DateTime Date { get; private set; } 
    public decimal Value { get; private set; } 

    public Item(DateTime date, decimal value) { 
    Date = date; 
    Value = value; 
    } 
} 

由於這兩種方法做同樣的事情,我想只有一個方法,我通過IEnumerable和聚合函數(總和/最大)作爲參數。我怎樣才能做到這一點?

回答

8

請嘗試以下

public IEnumerable<Item> DoStuff(
    IEnumerable<Item> someItems, 
    Func<IGrouping<DateTime,decimal>,Item> reduce) { 
    var items = someItems.GroupBy(i => i.Date).Select(reduce); 
    ... 
} 

DoStuff(someItems, p => p.Sum(r => r.Value)); 
DoStuff(someItems, p => p.Max(r => r.Value)); 
2

內部增加了選擇器是一件很痛苦的事情,但最終你可以採取Func<IEnumerable<decimal>,decimal>,並通過Enumerable.MaxEnumerable.Sum作爲委託實例。要做到這一點沒有複製=>r.Value選擇需要先做選擇,即

// usage: 
DoStuff(items, Enumerable.Sum); 
DoStuff(items, Enumerable.Max); 
// shared method: 
public IEnumerable<Item> DoStuff(IEnumerable<Item> someItems, 
     Func<IEnumerable<decimal>,decimal> aggregate) 
{ 
    var items = someItems.GroupBy(i => i.Date).Select(
     p => new Item(p.Key, aggregate(p.Select(r=>r.Value)))); 
    ... 
} 
1

哎呀!:

public IEnumerable<Item> DoOtherStuff(IEnumerable<Item> someItems, 
    Func< 
     IGrouping<DateTime, Item>, 
     Func<Func<Item, decimal>, decimal> 
     > aggregateForGrouping 
    ) 
{ 
    var items = someItems.GroupBy(i => i.Date) 
     .Select(p => new Item(p.Key, aggregateForGrouping(p)(r => r.Value))); 
    // ... 
} 

DoOtherStuff(someItems, p => p.Max); 

嗯,不做到這一點,做JaredPar說的...

或者如果您仍想獲取此語法,請使用一些嚴重的別名。

using ItemGroupingByDate = IGrouping<DateTime, Item>; 
using AggregateItems = Func<Func<Item, decimal>, decimal>; 

public IEnumerable<Item> DoOtherStuff(
    IEnumerable<Item> someItems, 
    Func<ItemGroupingByDate, AggregateItems> getAggregateForGrouping 
    ) 
{ 
    var items = someItems.GroupBy(i => i.Date) 
     .Select(p => new Item(p.Key, getAggregateForGrouping(p)(r => r.Value))); 
    // ... 
} 

它可能幾乎是可讀的,如果你能在其他別名使用別名,或具有匹配Func鍵簽名匹配定製的代表,那麼你可以在那裏大灌籃「選擇」,而不是「功能」的。

儘管如此,我們仍然處於一個兔子洞中,所以這不是您要尋找的解決方案。只是爲了演示:)

+0

+1 - 雖然我喜歡,但方法簽名變得太難閱讀,即使有別名。 – Fernando 2010-08-18 11:57:58