重用 LINQ 查询

Reuse of a LINQ query

这不是关于结果的重用,而是关于语句本身。 也不是关于使用 var 时的错误,如:LINQ to SQL: Reuse lambda expression

出于纯粹的好奇心,我想知道是否可以重用单个 LINQ 语句。

假设我有以下 LINQ 语句:

.Where(x => x.Contains(""));

是否可以提取语句 x => x.Contains("") 并使用某种对此的引用供以后使用,比方说,另一个 class?

所以我可以这样称呼它:.Where(previouslySavedStatement);

您可以将其存储在变量中。如果您使用 IQueryable 则使用:

System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");

如果您使用 IEnumerable 则使用:

Func<Foo, bool> selector = x => x.Contains("");

并在您的查询中使用它:

query.Where(selector);

视情况而定。有两种 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);

是的,您可以编写一个包含要重复使用的查询的函数,该函数采用 returns 一个 IQueryable

   public IQueryable<T> ContainsEmpty(IQueryable<T> query)
   {
       return query.Where(x => x.Contains(""));
   }

现在您可以重复使用它了:

   query1 = ContainsEmpty(query1);
   query2 = ContainsEmpty(another);

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

它允许创建查询片段并在 linq 查询中的任何地方使用它们。按照 Hamid 的示例,创建以下表达式:

System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");

您现在可以像这样在 linq 查询中的任何地方使用此查询:

query.AsComposable().Where(o => selector.Pass(o));

除了这个简单的示例之外,您还可以组合查询片段:

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

甚至将它们合并在一起:

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

还有一些功能,但我认为它真的很有用,所以请检查一下:)