7

我有几个Expression<Func<User,bool>>共享属性的表达式。例如,

Expression<Func<User, bool>> e1 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != null;
Expression<Func<User, bool>> e2 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "A";
Expression<Func<User, bool>> e3 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "B";

有没有一种简单的方法可以将变量放入u.IsActive && u.Group != "PROCESS"变量中并在 e1、e2 和 e3 中使用它?编辑:我仍然想要同一棵树。

似乎我可以通过使用Expression.Lambda<Func<User, bool>>(BinaryExpression.AndAlso(etc 构建表达式来做到这一点......但不是简化我的代码,而是让它更难阅读。

4

4 回答 4

3

我相信对于您的情况没有更清洁的方法可以做到这一点。你可以使用BinaryExpression你提到的。BinaryExpression您可以将and调用封装Expression.Lambda到一个方法中并调用它(如PredicateBuilder.And),但这些都不像当前的语法 IMO 那样干净。

于 2009-09-17T13:39:12.797 回答
3

lambda 表达式的问题是它们是不可变的,你不能轻易地替换 lambda 的参数。我最初的想法是做这样的事情(不幸的是,这不会成功):

public static class ExpressionExtesions
{
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> baseCondition, Expression<Func<T, bool>> additionalCondition)
    {
        var and = Expression.AndAlso(baseCondition.Body, additionalCondition.Body);
        return Expression.Lambda<Func<T, bool>>(and, baseCondition.Parameters);  // additionalCondition.Body still uses its own parameters so this fails on Compile()
    }
}

并在代码中使用:

Expression<Func<User, bool>> e = usr => usr.IsActive && usr.Group != "PROCESS";

var e1 = e.And(u => u.Name != null);
var e2 = e.And(u => u.Name != "A");
var e3 = e.And(u => u.Name != "B");

可能的解决方案

您可以尝试使用旨在实现表达式构建器的项目之一。我没有使用过其中任何一个,但谷歌提供了很多链接,例如:

另一种方法

如果您在 LINQ 中使用这些表达式来过滤值,则可以使用不同的方法(不要组合表达式,而是组合过滤器):

var activeUsers = allUsers.Where(usr => usr.IsActive && usr.Group != "PROCESS");

var usersAll = activeUsers.Where(u => u.Name != null);
var usersNotA = activeUsers.Where(u => u.Name != "A");
var usersNotB = activeUsers.Where(u => u.Name != "B");
于 2009-09-17T14:35:45.260 回答
2

我认为不一定有比您已经使用的答案更好的答案。正如 Mehrdad 提到的,您必须使用 BinaryExpression 构建更深的树,我认为这将是您当前代码可读性的倒退。

根据您的使用情况,您可以通过利用闭包语​​义并执行以下操作来节省一些代码行:

string name = null;

Expression<Func<User, bool>> e = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != name;

var expr = e.Compile();

name = "A";
var result = expr.Invoke(u); //True (assume u.Name = "B")

name = "B";
result = expr.Invoke(u); //False

...但这是否有用取决于您对已编译委托的处理。可能对您完全没用,但值得一提以防万一!

于 2009-09-17T13:55:10.440 回答
1
var test = new Func<User, bool>(u=> u.IsActive && u.Group != "PROCESS");
Expression<Func<User, bool>> e1 = (User u) => test(u) && u.Name != null;
Expression<Func<User, bool>> e2 = (User u) => test(u) && u.Name != "A";
Expression<Func<User, bool>> e3 = (User u) => test(u) && u.Name != "B";
于 2009-09-17T13:30:20.003 回答