- System.Linq.Expressions命名空间包含了代表表达式的各个类,它们都继承自Expression
- Expression类包含两个属性
- Type属性代表表达式求值后的.NET类型,可把它视为一个返回类型,例如,如果一个表达式要获取一个字符串的Length属性,该表达式的类型是int。
- NodeType属性返回所代表的表达式的种类。它是ExpressionType枚举的成员,包括LessThan, Multiply和Invoke等。仍然使用上面的例子,对于MyString.Length这个属性访问来说,其节点类型是MemberAccess。
private static void TestExpression() { Expression firstArg = Expression.Constant(2); Expression secondArg = Expression.Constant(3); Expression add = Expression.Add(firstArg, secondArg); Console.WriteLine(add); }
private static void TestExpression() { Expression firstArg = Expression.Constant(2); Expression secondArg = Expression.Constant(3); Expression add = Expression.Add(firstArg, secondArg); Func<int> compiled = Expression.Lambda<Func<int>>(add).Compile(); Console.WriteLine(add); }
- 简单加法表达式就是一个不获取任何参数,并返回整数的委托。与之匹配的签名就是Func<int>,所以可以使用一个Expression<Func<int>>。
private static void TurnLambdatoExpression() { Expression<Func<int>> return5 = () => 5; Func<int> compiled = return5.Compile(); Console.WriteLine(compiled()); }
- 并非所有的Lambda表达式都能转换成表达式树。不能将带有一个语句块(即使只有一个return语句)的Lambda转换成表达式树
- 只有对单个表达式进行求值的Lambda才可以。
- 表达式中还不能包含赋值操作。
private static void ManuallyCreateExpression() { MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); var target = Expression.Parameter(typeof(string), "x"); var methodArg = Expression.Parameter(typeof(string), "y"); Expression[] methodArgs = new[] { methodArg }; Expression call = Expression.Call(target, method, methodArgs); var lambdaParameters = new[] { target, methodArg }; var lambda = Expression.Lambda<Func<string, string, bool>>(call, lambdaParameters); var compiled = lambda.Compile(); Console.WriteLine(compiled("First", "Second")); Console.WriteLine(compiled("First", "Fir")); }
- 为了构造最终的方法调用表达式,我们需要知道方法调用的几个部件:方法的目标(调用StartsWith的字符串),方法本身(MethodInfo);参数列表(本例只有一个参数)。
- 将方法调用构造成一个表达式之后,接着需要把它转化成Lambda。
- LINQ提供的中心思想在于,我们可以从一个熟悉的源语言(C#)生成一个表达式树,将结果作为一个中间格式,再将其转换成目标平台上的本地语言,比如SQL。
- 优化动态语言运行时
- 可以放心的对成员的引用进行重构
- 更简单的反射