如何将谓词表达式分解为查询?

我有以下类Person ,带有自定义Where方法:

 public class Person { public string Name { get; set; } public int Age { get; set; } public string Where(Expression<Func> predicate) { return String.Empty; } } 

如何以可枚举的方式检索Expression参数名称和值?

 Person p = new Person(); p.Where(i => i.Name == "Shlomi" && i.Age == 26); 

用于根据表达式的名称和值构建带有参数的字符串查询。

 // Eventually I will convert the above into the following: string Query = "select * from person where name = @Name AND Age = @Age"; SqlParameter[] param = new SqlParameter[] { new SqlParameter("@Name","Shlomi"), new SqlParameter("@Age","26") }; 

我当然认为你应该遵循StriplingWarrior的建议并使用LINQ to Entities或LINQ to SQL,但为了重新发明轮子(糟糕的是),我将建立我的先前答案 。

 // Start with a method that takes a predicate and retrieves the property names static IEnumerable GetColumnNames(Expression> predicate) { // Use Expression.Body to gather the necessary details var members = GetMemberExpressions(predicate.Body); if (!members.Any()) { throw new ArgumentException( "Not reducible to a Member Access", "predicate"); } return members.Select(m => m.Member.Name); } 

现在,您需要遍历表达式树,访问每个候选表达式,并确定它是否包含MemberExpression 。 下面的GetMemberExpressions方法将遍历表达式树并检索在以下MemberExpression找到的每个MemberExpression

 static IEnumerable GetMemberExpressions(Expression body) { // A Queue preserves left to right reading order of expressions in the tree var candidates = new Queue(new[] { body }); while (candidates.Count > 0) { var expr = candidates.Dequeue(); if (expr is MemberExpression) { yield return ((MemberExpression)expr); } else if (expr is UnaryExpression) { candidates.Enqueue(((UnaryExpression)expr).Operand); } else if (expr is BinaryExpression) { var binary = expr as BinaryExpression; candidates.Enqueue(binary.Left); candidates.Enqueue(binary.Right); } else if (expr is MethodCallExpression) { var method = expr as MethodCallExpression; foreach (var argument in method.Arguments) { candidates.Enqueue(argument); } } else if (expr is LambdaExpression) { candidates.Enqueue(((LambdaExpression)expr).Body); } } } 

问题是Expression实际上是一棵树。

例如,您有以下谓词:

 Expression> expr = x => x.Name == "Shlomi" && x.Age == 26; 

如果检查expr,你会看到它的主体有“AndAlso” NodeType ,它还有两个操作数属性 – LeftRight各自指向另一个具有“Equal” NodeType Expression对象,而NodeType又有两个属性LeftRight指向MemberAccessConstant类型的Expression

虽然您可以处理该树并提取所需的所有信息,但您最终将实现自己的LINQ2SQL提供程序,例如重新发明轮子。 如果您有这种感觉,我希望我提供了足够的信息来开始挖掘……

你想要做的事情非常复杂,并且有完整的框架可以做到这一点,所以你不必自己编写逻辑。 看一下LINQ to Entities和LINQ to SQL,例如