重用 LINQ 查询
Posted
技术标签:
【中文标题】重用 LINQ 查询【英文标题】:Reuse of a LINQ query 【发布时间】:2016-03-24 01:56:47 【问题描述】:这不是关于结果的重用,而是语句本身。 也不是关于使用 var 时出现的错误,如:LINQ to SQL: Reuse lambda expression
出于纯粹的好奇,我想知道是否可以重用单个 LINQ 语句。
假设我有以下 LINQ 语句:
.Where(x => x.Contains(""));
是否可以提取语句 x => x.Contains("")
并使用对此的某种引用以供以后在另一个类中使用?
所以我可以这样称呼它:.Where(previouslySavedStatement);
【问题讨论】:
把它放在一个变量中。Func<string, bool> func = x => x.contains("");
@wudzik 这不是重复的。重复引用是指重用结果,问题询问重用查询本身。
@Shlomo 抱歉,误解了问题,重新打开
Func<string, bool> previouslySavedStatement = x => x.Contains("")
或 Expression<Func<string, bool>>
如果源是 IQueryable
。
LINQ to SQL: Reuse lambda expression的可能重复
【参考方案1】:
您可以将其存储在变量中。如果您使用的是IQueryable
,请使用:
System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");
如果您使用的是IEnumerable
,请使用:
Func<Foo, bool> selector = x => x.Contains("");
并在您的查询中使用它:
query.Where(selector);
【讨论】:
仅供参考 @Blaatz0r 如果您使用的是IEnumerable<T>
而不是 IQueryable<T>
,您只会使用 Func<Foo, bool> selector = ...
,但如果您使用的是 IQueryable<T>
,您最想使用Expression<Func<Foo, bool>>
版本。
@ScottChamberlain 我的大部分陈述都是 IEnumerableFunc<Foo, bool> selector2 = selector.Compile();
将其转换为委托,你不能从委托到表达式的另一个方向。【参考方案2】:
这取决于。有两个Where
方法,Enumerable.Where
和Queryable.Where
。如果您将.Where
应用于IEnumerable
,则调用第一个,如果您将其应用于IQueryable
,则调用第二个。
由于Enumerable.Where
接受Func
,因此它不可重复使用。因为Queryable.Where
接受一个表达式,所以它是可重用的。你可以这样做:
var x = new List<string>().AsQueryable();
var query = x.Where (n => n.Contains("some string"));
//Extract the lambda clause
var expr = query.Expression;
var methodExpr = (MethodCallExpression)expr;
var quoteExpr = (UnaryExpression)methodExpr.Arguments[1];
var funcExpr = (Expression<Func<string, bool>>)quoteExpr.Operand;
您可以稍后重新应用 where 表达式:
var query2 = x.Where(funcExpr);
【讨论】:
是的,我什至阅读了接受的答案,我什至也阅读了问题。我什至相信我的回答比接受的答案更好地回答了这个问题。var methodExpr = (MethodCallExpression)expr;
似乎不如MethodCallExpression methodExpr = expr;
那么干净【参考方案3】:
是的,您可以编写一个包含您想要重用的查询的函数,该函数接受并返回一个 IQueryable
public IQueryable<T> ContainsEmpty(IQueryable<T> query)
return query.Where(x => x.Contains(""));
现在你可以重复使用它了:
query1 = ContainsEmpty(query1);
query2 = ContainsEmpty(another);
【讨论】:
+1 这并不能直接回答 OP 的问题,但这是解决他的问题的更好方法(不过,你为什么选择IQueryable<T>
而不是IEnumerable<T>
?)我>
问题中没有指定数据类型,但它确实提到了“LINQ to SQL”并且标题中有“查询”,所以我猜是 IQueryable :-)【参考方案4】:
我写了一个库来解决这个问题,它叫做 CLinq,你可以在这里找到 EntityFramework 的实现:https://www.nuget.org/packages/CLinq.EntityFramework
它允许创建查询 sn-ps 并在 linq 查询中随处使用它们。按照 Hamid 的示例,创建以下表达式:
System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");
您现在可以在 linq 查询中的任何地方使用此查询,如下所示:
query.AsComposable().Where(o => selector.Pass(o));
除了这个简单的例子,你还可以结合你的查询 sn-ps:
query.AsComposable().Where(o => selector.Pass(o) || anotherSelector.Pass(o));
甚至将它们合并在一起:
query.AsComposable().Where(o => anotherSelector.Pass(selector.Pass(o)));
还有一些功能,但我认为它真的很有帮助,所以看看吧:)
【讨论】:
以上是关于重用 LINQ 查询的主要内容,如果未能解决你的问题,请参考以下文章