如何撰写现有的Linq表达式
时间:2020-03-05 18:50:34 来源:igfitidea点击:
我想组成两个Linq表达式的结果。它们以以下形式存在
Expression<Func<T, bool>>
因此,我要编写的两个对象本质上都是一个参数(类型T)的委托,它们都返回一个布尔值。我想组成的结果将是布尔值的逻辑评估。我可能会将其实现为扩展方法,因此我的语法将类似于:
Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; Expression<Func<User, bool>> expression2 = t => t.Age == 28; Expression<Func<User, bool>> composedExpression = expression1.And(expression2);
然后在我的代码中,我想评估组成的表达式
var user = new User(); bool evaluated = composedExpression.Compile().Invoke(user);
我提出了一些不同的想法,但我担心它比我希望的要复杂。这是怎么做的?
解决方案
回答
为什么不只使用Expression.And
并处理生成的BinaryExpression
?
Expression<Func<T, bool>> expr1 = t => t.Name == "steve"; Expression<Func<T, bool>> expr2 = t => t.Age == 28; Expression composed = Expression.And(expr1.Body, expr2.Body);
我们当然可以将其捆绑到一个lambda中以获得所需的签名,但这很昂贵,应该只执行一次,而不是多次:
Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>( expr, Expression.Parameter(typeof(T), "t") );
/编辑:当然,我们可以按以下方式组合lambda,但这涉及冗余的编译和函数调用:
Expression<Func<string, bool>> z = t => expr1.Compile()(t) && expr2.Compile()(t);
该死,维护停机时间。必须再次输入整个帖子。 :-/
/编辑:阿库是对的。我们必须分别调用expr2
,否则编译器将找不到参数引用。
回答
这是一个例子:
var user1 = new User {Name = "steve", Age = 28}; var user2 = new User {Name = "foobar", Age = 28}; Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; Expression<Func<User, bool>> expression2 = t => t.Age == 28; var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); var result = Expression.Lambda<Func<User, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); Console.WriteLine(result.Compile().Invoke(user1)); // true Console.WriteLine(result.Compile().Invoke(user2)); // false
我们可以通过扩展方法重用此代码:
class User { public string Name { get; set; } public int Age { get; set; } } public static class PredicateExtensions { public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,Expression<Func<T, bool>> expression2) { InvocationExpression invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); } } class Program { static void Main(string[] args) { var user1 = new User {Name = "steve", Age = 28}; var user2 = new User {Name = "foobar", Age = 28}; Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; Expression<Func<User, bool>> expression2 = t => t.Age == 28; var result = expression1.And(expression2); Console.WriteLine(result.Compile().Invoke(user1)); Console.WriteLine(result.Compile().Invoke(user2)); } }
回答
我们还可以使用LinqKit,它可以为我们完成所有这些工作。
http://www.albahari.com/nutshell/linqkit.aspx