我有两个看起来几乎相同的方法,除了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和聚合函数(sum / max)作为参数传递。我怎样才能做到这一点?
答案 0 :(得分: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));
答案 1 :(得分:2)
在里面添加选择器很麻烦,但最终你可以使用Func<IEnumerable<decimal>,decimal>
,并传入Enumerable.Max
或Enumerable.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))));
...
}
答案 2 :(得分: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签名匹配自定义委托,那么它几乎可以读取,那么您可以在其中阻塞“选择器”而不是“Func”。
尽管如此,我们仍然是一个兔子洞,所以这不是你想要的解决方案。只是为了演示目的放在这里:)