让我们用尝试构造Expression Tree来表达
context.Customers.Where(c => c.City == “London”)
01 // context.Customers
02 ConstantExpression customersExpr = Expression.Constant(context.Customers);
03 // 定义Customer c
04 ParameterExpression parameterExpr = Expression.Parameter(typeof(Customer), "c");
05 // 访问c.City属性?
06 MemberExpression cityExpr = Expression.Property(parameterExpr, "City");
07 // c.City == "London"
08 BinaryExpression equalExpr = Expression.Equal(cityExpr, Expression.Constant("London"));
09 // c => c.City == "London"
10 LambdaExpression conditionExpr = Expression.Lambda(equalExpr, parameterExpr);
11
12 // 注意: Where方法的签名是:
13 // Queryable.Where<T>(this IQueryable<T> source, Func<T, bool> predicate)
14 MethodCallExpression methodExpr = Expression.Call(
15 typeof(Queryable),
16 "Where",
17 new Type[] {typeof(Customer)},
18 customersExpr, conditionExpr
19 );
20
21 Console.WriteLine(methodExpr.ToString());
22 // 输出:Table(Customer).Where(c => (c.City = "London"))
另外一个有趣的是,在Queryable的源代码里有不少Expression.Quote()的调用,把a变成’(a)是什么意思? 来看看下面这段代码,分别表示() => 2 + 3和 () => ‘(2 + 3):
1 BinaryExpression expr = Expression.Add(
2 Expression.Constant(2), Expression.Constant(3));
3 var expr1 = Expression.Lambda<Func<int>>(expr);
4 var expr2 = Expression.Lambda<Func<BinaryExpression>>(Expression.Quote(expr));
5
6 Console.WriteLine(expr1.Compile()()); // 输出:5
7 Console.WriteLine(expr2.Compile()()); // 输出:(2 + 3)
Quote(A)的意思是,输出值为A表达式,而不是A表达式的计算值。
Lambda Expression
lambda expression可以是Expression Tree的一个节点,可以用来创建一个委托。但你知道如何用lambda expression来创建节点和委托吗?
01 LambdaExpression expr = () => 2 + 3; // 错误