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. 窗体控件 回车事件 分类: WinForm 2014-11-21 10:45 233人阅读 评论(0) 收藏

    说明: (1)设置窗体控件的TabIndex属性,(按回车顺序设置TabIndex的大小) (2)修改窗体的一个属性:KeyPreview=true //protected override void ...

  2. C# 字符串常用操作 分类: C# 2014-08-22 15:07 238人阅读 评论(0) 收藏

    string str1 = "C#操作字符串<几种常见方式>如下"; string str2 = "C#操作字符串";     //比较字符串 Co ...

  3. ASP.NET常用导出Excel方法汇总

    本文转载:http://mattberseth.com/blog/2007/04/export_gridview_to_excel_1.html http://geekswithblogs.net/a ...

  4. 个人收藏的flex特效网址【经典中的极品】

    http://www.noupe.com/adobe/flex-developers-toolbox-free-components-themes-and-tutorials.html经典中的经典 h ...

  5. List<T>分组一

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  6. SystemTap----常用变量、宏、函数和技巧

    http://blog.csdn.net/moonvs2010/article/category/1570309

  7. Linux sed命令常用方法

    sed也成stream editor,流编辑器,是Linux上常用的文本处理工具. 通用格式:sed  行范围  模式/RegExp/  文件 模式: d 删除 p 打印符合条件的行 a \strin ...

  8. HDU 4294 Multiple(搜索+数学)

    题意: 给定一个n,让求一个M,它是n个倍数并且在k进制之下 M的不同的数字最少. 思路: 这里用到一个结论就是任意两个数可以组成任何数的倍数.知道这个之后就可以用搜索来做了.还有一个问题就是最多找n ...

  9. ZOJ 3903 Ant(公式推导)

    这个公式推导过程是看的这位大牛的http://blog.csdn.net/bigbigship/article/details/49123643 扩展欧几里德求模的逆元方法: #include < ...

  10. (转)基于PHP的cURL快速入门

    1. 原文:基于PHP的cURL快速入门 英文原文:http://net.tutsplus.com/tutorial ... for-mastering-curl/ 原文作者:Burak Guzel ...