Expression Trees

只是想简单说下表达式树 - Expression Trees

目录

简介

  表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。

  你可以对表达式树中的代码进行编辑和运算。这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。 

  表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性。

一、Lambda 表达式创建表达式树

  若 lambda 表达式被分配给 Expression<TDelegate> 类型的变量,则编译器可以发射代码以创建表示该 lambda 表达式的表达式树。

  C# 编译器只能从表达式 lambda (或单行 lambda)生成表达式树。

  下列代码示例使用关键字 Expression创建表示 lambda 表达式:

1             Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
2 Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
3 Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;

二、API 创建表达式树

  通过 API 创建表达式树需要使用 Expression 类

  下列代码示例展示如何通过 API 创建表示 lambda 表达式:num => num == 0

1             //通过 Expression 类创建表达式树
2 // lambda:num => num == 0
3 ParameterExpression pExpression = Expression.Parameter(typeof(int)); //参数:num
4 ConstantExpression cExpression = Expression.Constant(0); //常量:0
5 BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression); //表达式:num == 0
6 Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression); //lambda 表达式:num => num == 0

  代码使用 Expression 类的静态方法进行创建。

三、解析表达式树

  下列代码示例展示如何分解表示 lambda 表达式 num => num == 0 的表达式树。

1             Expression<Func<int, bool>> funcExpression = num => num == 0;
2
3 //开始解析
4 ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
5 BinaryExpression body = (BinaryExpression)funcExpression.Body; //lambda 表达式主体:num == 0
6
7 Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

四、表达式树永久性

  表达式树应具有永久性(类似字符串)。这意味着如果你想修改某个表达式树,则必须复制该表达式树然后替换其中的节点来创建一个新的表达式树。  你可以使用表达式树访问者遍历现有表达式树。第七节介绍了如何修改表达式树。
 

五、编译表达式树

  Expression<TDelegate> 类型提供了 Compile 方法以将表达式树表示的代码编译成可执行委托。

1             //创建表达式树
2 Expression<Func<string, int>> funcExpression = msg => msg.Length;
3 //表达式树编译成委托
4 var lambda = funcExpression.Compile();
5 //调用委托
6 Console.WriteLine(lambda("Hello, World!"));
7
8 //语法简化
9 Console.WriteLine(funcExpression.Compile()("Hello, World!"));

六、执行表达式树

  执行表达式树可能会返回一个值,也可能仅执行一个操作(例如调用方法)。

  只能执行表示 lambda 表达式的表达式树。表示 lambda 表达式的表达式树属于 LambdaExpression 或 Expression<TDelegate> 类型。若要执行这些表达式树,需要调用 Compile 方法来创建一个可执行委托,然后调用该委托。
 1             const int n = 1;
2 const int m = 2;
3
4 //待执行的表达式树
5 BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
6 //创建 lambda 表达式
7 Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
8 //编译 lambda 表达式
9 Func<int> func = funcExpression.Compile();
10
11 //执行 lambda 表达式
12 Console.WriteLine($"{n} + {m} = {func()}");

七、修改表达式树

  该类继承 ExpressionVisitor 类,通过 Visit 方法间接调用 VisitBinary 方法将 != 替换成 ==。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。

 1     internal class Program
2 {
3 private static void Main(string[] args)
4 {
5 Expression<Func<int, bool>> funcExpression = num => num == 0;
6 Console.WriteLine($"Source: {funcExpression}");
7
8 var visitor = new NotEqualExpressionVisitor();
9 var expression = visitor.Visit(funcExpression);
10
11 Console.WriteLine($"Modify: {expression}");
12
13 Console.Read();
14 }
15
16 /// <summary>
17 /// 不等表达式树访问器
18 /// </summary>
19 public class NotEqualExpressionVisitor : ExpressionVisitor
20 {
21 public Expression Visit(BinaryExpression node)
22 {
23 return VisitBinary(node);
24 }
25
26 protected override Expression VisitBinary(BinaryExpression node)
27 {
28 return node.NodeType == ExpressionType.Equal
29 ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
30 : base.VisitBinary(node);
31 }
32 }
33 }

八、调试

  8.1 参数表达式

1             ParameterExpression pExpression1 = Expression.Parameter(typeof(string));
2 ParameterExpression pExpression2 = Expression.Parameter(typeof(string), "msg");

图8-1

图8-2

  从 DebugView 可知,如果参数没有名称,则会为其分配一个自动生成的名称。

1             const int num1 = 250;
2 const float num2 = 250;
3
4 ConstantExpression cExpression1 = Expression.Constant(num1);
5 ConstantExpression cExpression2 = Expression.Constant(num2);

图8-3

图8-4

  从 DebugView 可知,float 比 int 多了个后缀 F。

1             Expression lambda1 = Expression.Lambda<Func<int>>(Expression.Constant(250));
2 Expression lambda2 = Expression.Lambda<Func<int>>(Expression.Constant(250), "CustomName", null);

图8-5

图8-6

  观察 DebugView ,如果 lambda 表达式没有名称,则会为其分配一个自动生成的名称。


【原文链接】http://www.cnblogs.com/liqingwen/p/5868688.html

Expression Trees的更多相关文章

  1. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  2. Expression Trees 参数简化查询

    ASP.NET MVC 引入了 ModelBinder 技术,让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据,极大的方便了我们的编程,提高了生产力.在查询 Action ...

  3. 表达式树(Expression Trees)

    [翻译]表达式树(Expression Trees) 原文地址:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/con ...

  4. ASP.NET MVC:Expression Trees 作为参数简化查询

    ASP.NET MVC 引入了 ModelBinder 技术,让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据,极大的方便了我们的编程,提高了生产力.在查询 Action ...

  5. C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  6. Expression Trees (C# and Visual Basic)

    https://msdn.microsoft.com/en-us/library/bb397951.aspx Expression trees represent code in a tree-lik ...

  7. Expression Tree Basics 表达式树原理

    variable point to code variable expression tree data structure lamda expression anonymous function 原 ...

  8. 使用Expression做Linq的參數化排序

    Linq非常的好用,減少大量的資料庫操作手序,使用具名的類別,減少了在程式中寫SQL寫錯字的可能性,問題來了,如果我想用QueryString中的參數,作為排序的依據,但是因為是具名的類別,不能指定字 ...

  9. 不可不知的表达式树(1)Expression初探

    说起Lambda表达式,大家基本都很熟悉了,而表达式树(Expression Trees),则属于80%的工作中往往都用不到的那种技术,所以即便不是什么新技术,很多人对其理解都并不透彻.此文意图从表达 ...

随机推荐

  1. HTTP协议的特点

    HTTP协议的主要特点可概括如下: 1.支持客户/服务器模式.2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.POST.每种方法规定了客户与服务器联系的 ...

  2. SQL 存储过程 分页 分类: SQL Server 2014-05-16 15:11 449人阅读 评论(0) 收藏

    set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go -- ============================================= -- Au ...

  3. tl;drLegal ——开源软件license的搜索引擎

    TLDRLegal - Open Source Licenses Explained in Plain English可以很方便查询各个开源license的总结(能做什么,不能做什么),还能比较不同的 ...

  4. Python安装scipy

    1.下载numpy+mkl 下载链接:http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 2.下载scipy 下载链接:http://www.lfd.uc ...

  5. Android 官方文档:(二)应用清单 —— 2.2 &lt;action&gt;标签

    syntax: <action android:name="string" /> contained in: <intent-filter> descrip ...

  6. 写在新建博客的第一天 分类: fool_tree的笔记本 2014-11-08 17:57 144人阅读 评论(0) 收藏

    来CSDN开博客的目的有两个: 其一是因为CSDN的代码输出,看过一些博文,觉得这里的代码输出真的很漂亮: 其二则是因为,感觉自己印象笔记用久了之后,渐渐地几乎不再自己写些东西了,习惯了方便的剪藏插件 ...

  7. 高仿优酷Android客户端图片左右滑动(自动切换)

    本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能 ...

  8. 使用gulp在开发过程中合理导出zip文件

    最近一段时间一直在做桌面混合应用,跟以往做web端不同的是,无法再通过在浏览器上输入内部的域名来随时跟踪开发版本的状况了,只能通过打包代码让产品或领导随时跟踪进度. 这里就涉及到一些问题了: 1,需要 ...

  9. try、catch、finally与return

    1 try catch finally语句基础知识 finally一定会被执行. try块发生异常才会执行catch块. 如果finally块中抛出异常,则整个try.catch.finally块中抛 ...

  10. R cannot be resolved to a variable

    1. 检查Android 的SDK是否丢失需要重新下载,检查build path,把需要导入的JAR包确认都导入成功 2. 确保class没有import Android.R,注意是不能有Androi ...