zoukankan      html  css  js  c++  java
  • Linq之Expression高级篇(常用表达式类型)

    目录

    写在前面

    系列文章

    变量表达式

    常量表达式

    条件表达式

    赋值表达式

    二元运算符表达式

    一元运算符表达式

    循环表达式

    块表达式

    总结

    写在前面

    首先回顾一下上篇文章的内容,上篇文章介绍了表达式树的解析和编译。如果忘记了,可以通过下面系列文章提供的入口进行复习。这篇文章将介绍常见的表达式类型。

    常见的表达式类型都有个共同的基类Expression。创建这些类型的对象,是通过API的方式创建的(也就是Expression的静态方法),首先引入命名空间:

    1 using System.Linq.Expressions;

    系列文章

    Linq之Lambda表达式初步认识

    Linq之Lambda进阶

    Linq之隐式类型、自动属性、初始化器、匿名类

    Linq之扩展方法

    Linq之Expression初见

    Linq之Expression进阶

    变量表达式

    在表达式树中使用ParameterExpression或者ParameterExpression表达式表示变量类型,下面看一个例子,我们定义一个int类型的变量i:

      // ParameterExpression表示命名的参数表达式。
     ParameterExpression i = Expression.Parameter(typeof(int),"i");

    或者使用

    1 ParameterExpression j = Expression.Variable(typeof(int), "j");

    通过f12转到定义,发现这两个方法的注释几乎是一样的。静态方法Parameter第一个参数:定义的参数类型,第二个参数:为参数名称。

    常量表达式

    在表达式树中使用ConstantExpression表达式表示具有常量值的表达式。,看一个例子,我们定义一个int类型的常量5.并将该值赋值给上面定义的变量i

    1             // ParameterExpression表示命名的参数表达式。
    2             ParameterExpression i = Expression.Parameter(typeof(int), "i");
    3             //ParameterExpression j = Expression.Variable(typeof(int), "j");
    4             ConstantExpression constExpr = Expression.Constant(5, typeof(int));
    5             // 创建一个表示赋值运算的 System.Linq.Expressions.BinaryExpression
    6             //表示包含二元运算符的表达式。
    7             BinaryExpression binaryExpression = Expression.Assign(i, constExpr);

    Constrant方法第一个参数:常量,第二个参数为什么类型的常量。

    这里提到了BinaryExpression表达式,该表达式标识包含二元运算符的表达式,类似与=,>这样的二元表达式都可以使用BinaryExpression表达式来表示。

    调试模式下,在自动窗口查看当前表达式的DebugView属性,这个属性在调试表达式树的时候是非常有用的:

    变量:

    常量:

    二元表达式:

    通过观察上面的图,可知变量调试模式下DebugView属性将显示前面带有“$”符号的 ParameterExpression 变量名称。那么如果参数没有名称,则会为其分配一个自动生成的名称,例如 $var1 或 $var2(这里不再举例)。

    条件表达式

    在很多时候,我们都需要使用条件表达式来过滤一些数据,然后返回满足条件的数据,在表达式中有这样一些表达式满足你的需求。

    常见运算符

    >,>=

    <,<=

    if....then:如果满足条件那么..

    if...then...else:如果满足条件执行某某代码,否则执行另外的逻辑

    一个例子

    IfThenElse方法

    1 public static ConditionalExpression IfThenElse(
    2     Expression test,
    3     Expression ifTrue,
    4     Expression ifFalse
    5 )
     1             bool test = true;
     2             ConditionalExpression codition = Expression.IfThenElse(
     3                 //条件
     4                 Expression.Constant(test),
     5                 //如果条件为true,调用WriteLine方法输出“条件为true”
     6                  Expression.Call(
     7                  null,
     8                  typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
     9                  Expression.Constant("条件为true")
    10                  ),
    11                 //如果条件false
    12                   Expression.Call(
    13                  null,
    14                  typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    15                  Expression.Constant("条件为false")
    16                  )
    17                  );
    18             //编译表达式树,输出结果
    19             Expression.Lambda<Action>(codition).Compile()();

    输出结果

     例子描述:条件test包装为常量表达式,因为test为true,所以执行iftrue的表达式,并调用WriteLine方法打印出信息。

    赋值表达式

    =

    还以上面为变量i赋值的例子为例

    1             ParameterExpression i = Expression.Parameter(typeof(int), "i");
    2             //ParameterExpression j = Expression.Variable(typeof(int), "j");
    3             ConstantExpression constExpr = Expression.Constant(5, typeof(int));
    4             // 创建一个表示赋值运算的 System.Linq.Expressions.BinaryExpression
    5             //表示包含二元运算符的表达式。
    6             BinaryExpression binaryExpression = Expression.Assign(i, constExpr);

    +=

    1 BinaryExpression b2 = Expression.AddAssign(i, constExpr);

    -=

    1 BinaryExpression b3 = Expression.SubtractAssign(i, constExpr);

    *=

     BinaryExpression b4 = Expression.MultiplyAssign(i, constExpr);

    /=

    1 BinaryExpression b5= Expression.DivideAssign(i, constExpr);

    举一个例子

     1  ParameterExpression i = Expression.Parameter(typeof(int), "i");
     2             BlockExpression block = Expression.Block(
     3                 new[] { i },
     4                 //赋初值 i=5
     5                 Expression.Assign(i, Expression.Constant(5, typeof(int))),
     6                 //i+=5 10
     7                 Expression.AddAssign(i, Expression.Constant(5, typeof(int))),
     8                 //i-=5 5
     9                 Expression.SubtractAssign(i, Expression.Constant(5, typeof(int))),
    10                 //i*=5 25
    11                Expression.MultiplyAssign(i, Expression.Constant(5, typeof(int))),
    12                 //i/=5 5
    13                Expression.DivideAssign(i, Expression.Constant(5, typeof(int)))
    14                );
    15             Console.WriteLine(Expression.Lambda<Func<int>>(block).Compile()());

    结果

    二元运算符表达式

    在上面也提到了部分二元运算符表达式,类似加减乘除这样的运算符,对于二元运算符,就不再举例。这些返回的表达式树,都可以使用BinaryExpression来接收,或者使用基类Expression接收,或者更省事,使用var关键字。

    一元运算符表达式

    类似++,--运算符

    i++等价于i=i+1,运算顺序就是i先加1,然后再赋值给i。在表达式书中使用Expression的PostIncrementAssign方法来进行自增或者自减操作。返回结果为UnaryExpression类型,同样可以使用基类Expression接收,或者var。

    循环表达式

    在表达式树中使用Expression的Loop方法实现循环。

    块表达式

    在前面的文章中,也说了不能使用Lambda方式创建带块级的表达式树,不然会有如下的错误

    通过API的方式可以创建块级表达式树,其中Expression的Block方法功不可没。例如上面的加减乘除的例子中,可以包括多个Expression。

    那么,下面就举一个包含自增的一元表达式,循环的表达式块,并输出结果。

    输出1-100之间的所有偶数。

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             //变量i
     6             ParameterExpression i = Expression.Parameter(typeof(int), "i");
     7             //跳出循环
     8             LabelTarget label = Expression.Label();
     9             BlockExpression block = Expression.Block(
    10                 new[] { i },
    11                 //为i赋初值
    12                 Expression.Assign(i, Expression.Constant(1, typeof(int))),
    13                 Expression.Loop(
    14                     Expression.IfThenElse(
    15                       //如果i<=100
    16                       Expression.LessThanOrEqual(i, Expression.Constant(100, typeof(int))),
    17                      //如果为true.进入循环体
    18                         Expression.Block(
    19                              Expression.IfThen(
    20                              //条件i%2==0;
    21                                     Expression.Equal(Expression.Modulo(i, Expression.Constant(2, typeof(int))), 
    22                                     Expression.Constant(0, typeof(int))),
    23                                     Expression.Call(typeof(Console).GetMethod("WriteLine", 
    24                                     new Type[] { typeof(int) }), new[] { i })),
    25                              //i++
    26                              Expression.PostIncrementAssign(i)
    27                 ),
    28                 //如果i>100
    29                 Expression.Break(label)),
    30                 label
    31                 ));
    32             Expression.Lambda<Action>(block).Compile()();
    33             Console.Read();
    34         }
    35     }

    结果

    总结

    本篇文章介绍了几种常见的表达式类型,当然,还有很多并没有列出,比如switch case,try catch等。如果在项目中需要创建复杂的表达式树,Expression的静态方法Block是必不可少的。希望通过本篇的学习,对你了解Expression有所帮助。

    参考文章

    https://msdn.microsoft.com/zh-cn/library/dd323961(v=vs.110).aspx

    https://msdn.microsoft.com/zh-cn/library/bb397951.aspx

  • 相关阅读:
    Oracle:SQL语句--撤销用户权限
    Oracle:SQL语句--给用户赋权限
    RSTP端口状态迁移过程详解
    LSB算法分析与实现
    工厂方法模式
    Ceasar
    区域性名称和标识符
    Packet Tracer网络模拟实验实记
    H3C-OSPF
    H3C-RIP
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4234747.html
Copyright © 2011-2022 走看看