LINQ - 编写扩展方法来获取每组具有最大值的行
我的应用程序经常需要对表进行分组,然后返回该组中具有最大值的行。这在 LINQ 中很容易做到:
myTable.GroupBy(r => r.FieldToGroupBy)
.Select(r => r.Max(s => s.FieldToMaximize))
.Join(
myTable,
r => r,
r => r.FieldToMaximize,
(o, i) => i)
现在假设我想将其抽象为它自己的方法。我试着写这个:
public static IQueryable<TSource>
SelectMax<TSource, TGroupKey, TMaxKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TGroupKey>> groupKeySelector,
Expression<Func<TSource, TMaxKey>> maxKeySelector)
where TMaxKey : IComparable
{
return source
.GroupBy(groupKeySelector)
.Join(
source,
g => g.Max(maxKeySelector),
r => maxKeySelector(r),
(o, i) => i);
}
不幸的是,这不能编译:maxKeySelector是一个表达式(所以你不能在r上调用它,你甚至不能将它传递给Max。所以我尝试重写,使maxKeySelector成为一个函数而不是一个表达式:
public static IQueryable<TSource>
SelectMax<TSource, TGroupKey, TMaxKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TGroupKey>> groupKeySelector,
Func<TSource, TMaxKey> maxKeySelector)
where TMaxKey : IComparable
{
return source
.GroupBy(groupKeySelector)
.Join(
source,
g => g.Max(maxKeySelector),
r => maxKeySelector(r),
(o, i) => i);
}
“查询运算符“Max”不支持重载。”这就是我所坚持的:我需要找到将 maxKeySelector 传递到 Max() 的正确方法。
现在可以编译了。但在运行时失败: ?我正在使用 LINQ to SQL,这似乎有所作为。
My application frequently needs to group a table, then return the row with the maximum value for that group. This is pretty easy to do in LINQ:
myTable.GroupBy(r => r.FieldToGroupBy)
.Select(r => r.Max(s => s.FieldToMaximize))
.Join(
myTable,
r => r,
r => r.FieldToMaximize,
(o, i) => i)
Now suppose I want to abstract this out into its own method. I tried writing this:
public static IQueryable<TSource>
SelectMax<TSource, TGroupKey, TMaxKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TGroupKey>> groupKeySelector,
Expression<Func<TSource, TMaxKey>> maxKeySelector)
where TMaxKey : IComparable
{
return source
.GroupBy(groupKeySelector)
.Join(
source,
g => g.Max(maxKeySelector),
r => maxKeySelector(r),
(o, i) => i);
}
Unfortunately this doesn't compile: maxKeySelector is an expression (so you can't call it on r, and you can't even pass it to Max. So I tried rewriting, making maxKeySelector a function rather than an expression:
public static IQueryable<TSource>
SelectMax<TSource, TGroupKey, TMaxKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TGroupKey>> groupKeySelector,
Func<TSource, TMaxKey> maxKeySelector)
where TMaxKey : IComparable
{
return source
.GroupBy(groupKeySelector)
.Join(
source,
g => g.Max(maxKeySelector),
r => maxKeySelector(r),
(o, i) => i);
}
Now this compiles. But it fails at runtime: "Unsupported overload used for query operator 'Max'." This is what I'm stuck on: I need to find the right way to pass maxKeySelector into Max().
Any suggestions? I'm using LINQ to SQL, which seems to make a difference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,我想指出,您在 LINQ 中尝试做的事情比您想象的更容易:
...这应该使我们的第二部分的生活更轻松一些:
关键是,通过使您的组成为
IQueryable
,您可以打开一组新的 LINQ 方法,这些方法可以采用实际表达式而不是采用Func
。这应该与大多数标准 LINQ 提供程序兼容。First of all, I'd like to point out that what you're trying to do is even easier than you think in LINQ:
... which should make our lives a little easier for the second part:
The key is that by making your group an
IQueryable
, you open up a new set of LINQ methods that can take actual expressions rather than takingFunc
s. This should be compatible with most standard LINQ providers.非常有趣。有时,“动态”在纯粹的开发和运行时执行方面可能会花费您比其价值更高的成本(恕我直言)。尽管如此,这是最简单的:
而且,这是最动态的方法:
如您所见,我在扩展方法前面加了下划线。当然,您不需要这样做。只需采取总体想法并付诸实施即可。
你可以这样称呼它:
祝你好运!
Very interesting. Sometimes "dynamic" can cost you more in sheer development and runtime execution than it is worth (IMHO). Nonetheless, here's the easiest:
And, here's the most dynamic approach:
As you can see, I precede my Extension Methods with an underscore. You do not need to do this, of course. Just take the general idea and run with it.
You would call it like this:
Best of luck!