2010-08-17 73 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