重用 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.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);
是的,您可以编写一个包含要重复使用的查询的函数,该函数采用 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)));
还有一些功能,但我认为它真的很有用,所以请检查一下:)
这不是关于结果的重用,而是关于语句本身。 也不是关于使用 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.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);
是的,您可以编写一个包含要重复使用的查询的函数,该函数采用 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)));
还有一些功能,但我认为它真的很有用,所以请检查一下:)