C#表达式树的基本用法讲解

表达式树使用一种类似树的结构来表示代码,它的每个节点都是一个表达式,比如方法调用和x<y这样的二元运算等。我们可以对表达式树的内容进行编辑和运算,这样能够动态修改可执行代码,以及动态创建查询等。我们可以使用匿名lambda表达式或者C# API来创建表达式树。

这一系列文章,主要是对C#表达式树的一种总结,基本知识参考MSDN的内容 这部分内容可以直接到MSDN上查看,后面的几篇文章主要分享一下,在工作中碰到的应用到表达式树的部分,谨做为记录和分享。

生成表达式树

通过lambda表达式创建表达式树
    可以通过将lambda表达式赋值给Expression<TDelegate>类型的变量,编译器可以自动生成创建该lambda表达式的表达式树。C#编译器只能从lambda表达式生成表达式树,只能是单行lambda表达式,不能解析多行lambda语句,如下,可以通过一下方式创建lambda表达式 num=>num<5的表达式树:

Expression<Func<int, bool>> lambda = num => num < 5; 

通过API创建表达式树

使用API创建表达式,需要使用Expression类,这个类包含了创建特定类型表达式树节点的静态工厂方法,比如表示参数的变量ParameterExpression,表示方法调用的MethodExpression。ParameterExpression,MethodExpression以及其他特定的表达式类型都在System.Linq.Expression命名空间里定义,这些类型都派生于Expression抽象类。

下面的例子是使用API方式创建num=>num<5的lambda表达式对应的表达式树:

ParameterExpression numPara = Expression.Parameter(typeof(int), "num");//参数num
ConstantExpression five = Expression.Constant(5, typeof(int));//常数5

BinaryExpression numLessThanFive = Expression.LessThan(numPara, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numPara });

从.NET Framework 4开始,表达式树API还支持赋值以及流程控制,比如循环,条件块和try ... catch块等。相对于通过lambda表达式创建表达式树,可以利用API创建更加复杂的表达式树,比如下面使用API创建数字阶乘的表达式树:

//参数value
ParameterExpression value = Expression.Parameter(typeof(int), "value");
//本地变量
ParameterExpression result = Expression.Parameter(typeof(int), "result");
//标签,用来跳出循环
LabelTarget label = Expression.Label(typeof(int));
//创建表达式块
BlockExpression block = Expression.Block(
 //添加本地参数result
 new[] { result },
 //result=1 赋值
 Expression.Assign(result, Expression.Constant(1)),
 //循环
 Expression.Loop(
  //循环条件
  Expression.IfThenElse(
   //如果 value>1
   Expression.GreaterThan(value, Expression.Constant(1)),
   //则 result*=value--;
   Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)),
   //否则跳出loop循环。跳到label的语句执行
   Expression.Break(label, result)
   ),
   label
  )
);
//编译表达式树
Func<int, int> factor = Expression.Lambda<Func<int, int>>(block, value).Compile();
//执行,输出结果120
Console.WriteLine(factor(5));

解析表达式树

在获取了表达式树之后,如何获取表达式树的每一个部分,这个在有些情况下非常有用,下面这个例子展示了如何获取num=>num<5的各个部分。

Expression<Func<int, bool>> expreTree = num => num < 5;

ParameterExpression param = (ParameterExpression)expreTree.Parameters[0];//num
BinaryExpression operation = (BinaryExpression)expreTree.Body;//<
ParameterExpression left = (ParameterExpression)operation.Left;//num
ConstantExpression right = (ConstantExpression)operation.Right;//5
                //output Decomposed expression: num => num LessThan 5
Console.WriteLine("Decomposed expression:{0} = > {1} {2} {3}", param.Name, left.Name, operation.NodeType, right.Value);

编译表达式树

Expression<TDelegate>类型有Compile方法,可以将表达式树编译成对应的TDelegate委托类型,使用方法如下:

// 创建表达式树
Expression<Func<int, bool>> expr = num => num < 5;
// 将表达式树编译成对应委托
Func<int, bool> result = expr.Compile();
//调用委托方法,输出True
Console.WriteLine(result(4));
//也可以直接编译后调用,输出True
Console.WriteLine(expr.Compile()(4));

再比如,下面例子演示了,创建一个表达式树,然后编译执行:

//创建表达式树的执行逻辑
BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));
//创建表达式树
Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);
//编译表达式树
Func<double> compileExpression = le.Compile();
//执行lambda表达式,获得结果8
double result = compileExpression();
Console.WriteLine(result);

表达式树的修改

表达式树是不可变对象(immutable),跟string类似,不能直接修改,只能复制一个然后重新构造。具体参考MSDN How to modify expression trees (C#).

结语

本篇全部内容参考MSDN上表达式树部分的内容,如果有基础建议直接看,这里只是个人作为笔记,也是表达式树的最基础部分,后文会介绍表达式树的一些用法。

以上就是C#表达式树的基本用法讲解的详细内容,更多关于C#表达式树的资料请关注我们其它相关文章!

(0)

相关推荐

  • c#反射表达式树模糊搜索示例

    复制代码 代码如下: public static Expression<Func<T, bool>> GetSearchExpression<T>(string SearchString)        {            Expression<Func<T, bool>> filter = null; if (string.IsNullOrEmpty(SearchString)) return null;            var l

  • C#简单实现表达式目录树(Expression)

    1.什么是表达式目录树 :简单的说是一种语法树,或者说是一种数据结构(Expression) 2.用Lambda声明表达式目录树: Expression<Func<int, int, int>> exp = (n, m) => n * m + 2; //表达试目录树的方法体只能是一行,不能有大括号.比如: //Expression<Func<int, int, int>> exp1 = (m, n) => // { // return m * n

  • C# 表达式目录树的应用详解

    使用表达式目录树实现两个不同类型的属性赋值: public class People { public int Age { get; set; } public string Name { get; set; } public int Id; } public class PeopleCopy { public int Age { get; set; } public string Name { get; set; } public int Id; } public class Class1 {

  • C# 快速高效率复制对象(表达式树)

    1.需求 在代码中经常会遇到需要把对象复制一遍,或者把属性名相同的值复制一遍. 比如: public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class StudentSecond { public int Id { get; set; } public string Name { get; set; } p

  • C#之Expression表达式树实例

    本文实例讲述了C#之Expression表达式树,分享给大家供大家参考.具体实现方法如下: 表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 复制代码 代码如下: Expression<Func<int, int, int, int>> expr = (x, y, z) => (x + y) / z; 2.编译表达式树,该方法将表达式树表示的代码编译成一个可执行

  • 浅谈c#表达式树Expression简单类型比较demo

    实例如下: using System; using System.Linq.Expressions; class DynamicPredicate { public static Expression<Func<T, T, bool>> Generate<T>(string op) { ParameterExpression x = Expression.Parameter(typeof(T), "x"); ParameterExpression y

  • C#表达式目录树示例详解

    1.表达式目录树 表达式目录树,在C#中是Expression来定义的,它是一种语法树,或者说是一种数据结构.其主要用于存储需要计算.运算的一种结构,它只提供存储功能,不进行运算.通常Expression是配合Lambda一起使用,lambda可以是匿名方法.Expression可以动态创建. 声明一个lambda表达式,其中可以指明类型,也可以是匿名方法: //Func<int, int, int> func = new Func<int, int, int>((m, n) =&

  • C#用表达式树构建动态查询的方法

    前文介绍了C#中表达式树的基本知识,在实际中,表达式树有很多用法,这里举几个例子,说明如何使用表达式树构建动态查询,从而扩展LINQ的查询方法. 在LINQ中,只要数据源实现了IQuerable<T>接口,表达式树就可以用来表示结构化查询.比如,LINQ提供了用来查询关系数据源的IQueryable<T>接口的实现,C#编译器在执行这类数据源查询时,会在运行时生成表达式树,然后,查询会遍历表达式树的数据结构,然后将其转换成针对特定数据源的合适的查询语言. 下面的几个例子演示了如何使

  • C# 表达式树Expression Trees的知识梳理

    目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达式树 调试 简介 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等. 你可以对表达式树中的代码进行编辑和运算.这样能够动态修改可执行代码.在不同数据库中执行 LINQ 查询以及创建动态查询. 表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性. 一.

  • C#表达式树的基本用法讲解

    表达式树使用一种类似树的结构来表示代码,它的每个节点都是一个表达式,比如方法调用和x<y这样的二元运算等.我们可以对表达式树的内容进行编辑和运算,这样能够动态修改可执行代码,以及动态创建查询等.我们可以使用匿名lambda表达式或者C# API来创建表达式树. 这一系列文章,主要是对C#表达式树的一种总结,基本知识参考MSDN的内容 这部分内容可以直接到MSDN上查看,后面的几篇文章主要分享一下,在工作中碰到的应用到表达式树的部分,谨做为记录和分享. 生成表达式树 通过lambda表达式创建表达

  • C#表达式树讲解

    表达式树的概念 表达式树的创建有 Lambda法 和 组装法. 学习表达式树需要 委托.Lambda.Func<> 基础. 表达式树 形状可以参考二叉树. 可以把表达式树理解成 数学表达式. 数学表达式的所有常量.符号为表达式树的底节点.每一次计算生成的结果是一个结点,或者说他们的共同结点就是他们应该进行的运算. 生成表达式树 表达式树的创建有 Lambda表达式法 和 组装法 为了方便,这里指定生成的表达式为 ( i * j ) + ( x * y ) 他们的运算是这样的 Lambda 生成

  • C#表达式树Expression基础讲解

    什么是表达式树 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等.可以对表达式树中的代码进行编辑和运算. 这样能够动态修改可执行代码.在不同数据库中执行 LINQ 查询以及创建动态查询. 表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET 之间的互操作性,同时保证编译器编写员能够发射表达式树而非 Microsoft 中间语言 (MSIL). 这段话是来自官网( [表达式树 (C#) | Microsoft Docs](

  • 全网最细 Python 格式化输出用法讲解(推荐)

    一.使用 print() 函数 在 Python 中,print() 函数支持格式化输出,与 C 语言的 printf 类似. 1. 格式化输出字符串和整数 [示例1]输出字符串 AmoXiang,并计算.输出它的字符长度 str1 = "%s.length = %d" % ("AmoXiang", len("AmoXiang")) print(str1) # 输出AmoXiang.length = 8 % 在字符串中表示格式化操作符,它后面必须

  • C# Lambda表达式及Lambda表达式树的创建过程

    每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不爱说话,默默承受着编程的巨大压力,除了技术上的交流外,他们不愿意也不擅长和别人交流,更不乐意任何人走进他们的内心! 题外话说多了,咱进入正题: 上一节中,我们讲到:在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,La

  • C#中Invoke的用法讲解

    C#中Invoke的用法() invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解. 首先说下,invoke和begininvoke的使用有两种情况: 1. control中的invoke.begininvoke. 2. delegrate中的invoke.begininvoke. 这两种情况是不同的,我们这里要讲的是第1种.下面我们在来说下.NET中对invoke和begininv

  • linux 中vim的用法讲解

    Vim 是 Linux 系统上的最著名的文本/代码编辑器,也是早年的 Vi 编辑器的加强版,而 gVim 则是其 Windows 版.它的最大特色是完全使用键盘命令进行编辑,脱离了鼠标操作虽然使得入门变得困难,但上手之后键盘流的各种巧妙组合操作却能带来极为大幅的效率提升. vim的命令的一些格式 1:vim xxx 直接打开一个xxx命名的vim文件,如果没有的话直接创建一个新的.默认光标定义到第一行 2:vim + xxx 打开光标并定义到最后一行 3:vim +num xxx 打开光标定义到

  • OGNL表达式基本语法与用法详解

    一.OGNL中的#.%和$符号 #.%和$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分.在这里我们简单介绍它们的相应用途. 1.#符号的三种用法 1)访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀.实际上,#相当于ActionContext. getContext():#session.msg表达式相当于ActionContext.getContext().getSessi

  • Java8新特性Lambda表达式的一些复杂用法总结

    简介 lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的"函数式编程". 它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数. 本文将介绍关于Java8 Lambda表达式的一些复杂用法,分享出来供大家参考学习,下面来一起看看详细的介绍: 复杂用法实例 传入数组ids,在list<Obj>上操作,找出Obj中id想匹配的,并且按

随机推荐