接续[上篇之预告]

本篇来讲讲,如何根据前面设计的查询描述器构造出可执行的表达式。正如标题所示,实现手段将采用Expression Lambda技术。

先来看看主角System.Linq.Expressions.Expression 长什么样,都有些什么东西,能做什么。 先看看它的类图:

  • System.Linq.Expressions.ConstantExpression 常量

  • System.Linq.Expressions.DefaultExpression 默认值

  • System.Linq.Expressions.IndexExpression 索引

  • System.Linq.Expressions.MemberExpression 成员(属性或字段)

  • System.Linq.Expressions.MethodCallExpression 方法调用

  • System.Linq.Expressions.ParameterExpression 参数

  • System.Linq.Expressions.UnaryExpression 一元运算

  • System.Linq.Expressions.BinaryExpression 二元运算

  • System.Linq.Expressions.LambdaExpression 委托

我们主要使用Expression这个类,它包含各种节点类型的 static工厂方法。特别是以下这些方法,对应了查询需要用到的逻辑、比较、数学,等各种运算操作。

逻辑运算
AndAlso(Expression, Expression)表示And逻辑运算
OrElse(Expression, Expression)表示Or逻辑运算
比较运算
LessThan(Expression, Expression)表示小于:”<"
LessThanOrEqual(Expression, Expression)表示大于等于:“<="
GreaterThan(Expression, Expression)表示大于:”>“
GreaterThanOrEqual(Expression, Expression)表示大等于:”>=”
Equal(Expression, Expression)表示等于:”=“
NotEqual(Expression, Expression)表示不等于:”!=”
IsTrue(Expression)测试表达式结果是否为“True”
IsFalse(Expression)测试表达式结果是否为“False”
Not(Expression)表示”Not”
数学运算
Add(Expression, Expression)加法
Subtract(Expression, Expression)减法
Multiply(Expression, Expression)乘法
Divide(Expression, Expression)除法
Modulo(Expression, Expression)模除
Power(Expression, Expression)幂运算
一些操作
Parameter(Type)包装一个类型为Type的参数
Call(Expression, MethodInfo, Expression, Expression)包装一个方法调用
Bind(MemberInfo, Expression)包装一个成员绑定,(属性或字段)
Quote(Expression)包装一个括号
MakeUnary(ExpressionType, Expression, Type)包装一个一元运算
MakeBinary(ExpressionType, Expression, Expression)包装一个二元运算
TypeAs(Expression, Type)包装一个显式引用或装箱转换,其中如果转换失败则提供“null”。
Coalesce(Expression, Expression, LambdaExpression)包装表示给定转换函数的聚结操作。
变量、常量、字段、属性
Default(Type)包装一个指定类型的默认值
Constant(Object, Type)包装一个常量
Assign(Expression, Expression)赋值操作
Variable(Type, String)包装一个变量定义
Property(Expression, MethodInfo)包装一个属性
Field(Expression, FieldInfo)包装一个字段
PropertyOrField(Expression, String)包装一个指定名称的字段或属性
要的就是这结果
Lambda(Expression, ParameterExpression[])包装一个委托,带有一个参数表达式数组。

以上仅列出了一部分,它涵盖了全部可能要使用到的函数,语句,欲详细了解可以直接乘坐火箭到微软官方网站查看。

这此函数或功能是有了,如何使用呢?来看个例子:将SQL:Table1.A > 5 and Table1.B=3,转成(Table1)=>Table1.A > 5 && Table1.B==3;

Expression的世界里一切都是Expression。因此首先要将Table1A5B3先包装成Expression

  • 开干之前先谈个对象
//实体类:  public class Table   {    public int A;    public int B;   }
  • 然后包装各种Expression
​    //将Table1包装成ParameterExpression:    var p=Expression.Parameter(typeof(Table1),"Table1");​    //将5、3这两个常量包装成ConstantExpression:    var num5=Expression.Constant(5,typeof(int));    var num3=Expression.Constant(3,typeof(int));​    //将两个属性包装成MemberExpression。    var a=Expression.PropertyOrField(p,"A")    var b=Expression.PropertyOrField(p,"B")​    //构造Table1.A>5:    var gt=Expression.GreaterThen(a,num5);     //构造Table1.A=3:    var eq=Expression.Equal(b,num3);        ​
  • 再构造两个比较式
  //构造Table1.A>5:  var gt=Expression.GreaterThen(a,num5);     //构造Table1.A=3:    var eq=Expression.Equal(b,num3);    
  • 加上逻辑And将两个比较式连接起来
    //构造Table1.A>5 && Table1.A=3    var exp=Expression.AndAlso(gt,eq);
  • 结果就要出来了
//结果就获得了:    var lambda=Expression.Lambda()    
  • 来来来,测试一下康康接果:
  /*===============来来来,测试一下:===============*/     var f=lambda.Compile();  var x=f.DynamicInvoke(new Table(){A=6,B=3});  var y = f.DynamicInvoke(new Table() { A = 2, B = 3 });  Console.WriteLine("x:{0}\ny:{1}",x,y);  Console.WriteLine("Lambda:{0}",lambda.ToString());         /*输出:    结果对吗?我也不知道,我撸得这么辛苦,先让电脑休息一下,各位看官只要Ctrl+C,Ctrl+V就可以看到了.    */
  • OK,其它各种操作,只要依葫芦画瓢便大功可成! 先爽一下!
  • 好,暂且爽到这里,欲看如何把括号弄成俄罗斯套娃,且看下回分解.
  • 随手点个赞,让我也爽爽,可好!