重用 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&lt;T&gt; 而不是 IQueryable&lt;T&gt;,您只会使用 Func&lt;Foo, bool&gt; selector = ...,但如果您使用的是 IQueryable&lt;T&gt;,您最想使用Expression&lt;Func&lt;Foo, bool&gt;&gt; 版本。 @ScottChamberlain 我的大部分陈述都是 IEnumerable 所以感谢您的提醒 @Blaatz0r 如果你有表达式版本,你也可以通过 Func&lt;Foo, bool&gt; selector2 = selector.Compile(); 将其转换为委托,你不能从委托到表达式的另一个方向。【参考方案2】:

这取决于。有两个Where 方法,Enumerable.WhereQueryable.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&lt;T&gt; 而不是IEnumerable&lt;T&gt;?)我> 问题中没有指定数据类型,但它确实提到了“LINQ to SQL”并且标题中有“查询”,所以我猜是 IQueryable :-)【参考方案4】:

我写了一个库来解决这个问题,它叫做 CLinq,你可以在这里找到 EntityFramework 的实现:https://www.nuget.org/packages/CLinq.EntityFramework

它允许创建查询 sn-ps 并在 linq 查询中随处使用它们。按照 Hamid 的示例,创建以下表达式:

System.Linq.Expressions.Expression&lt;Func&lt;Foo, bool&gt;&gt; selector = x =&gt; x.Contains("");

您现在可以在 linq 查询中的任何地方使用此查询,如下所示:

query.AsComposable().Where(o =&gt; selector.Pass(o));

除了这个简单的例子,你还可以结合你的查询 sn-ps:

query.AsComposable().Where(o =&gt; selector.Pass(o) || anotherSelector.Pass(o));

甚至将它们合并在一起:

query.AsComposable().Where(o =&gt; anotherSelector.Pass(selector.Pass(o)));

还有一些功能,但我认为它真的很有帮助,所以看看吧:)

【讨论】:

以上是关于重用 LINQ 查询的主要内容,如果未能解决你的问题,请参考以下文章

C# linq 如何编写子查询?

将 sql 查询转换为 linq 查询

C# linq 多表in语句查询

LINQ查询表达式 - LINQ 查询分组

Linq查询条件怎么查询呢

LINQ查询