C# 表达式树 创建、生成、使用、lambda转成表达式树~表达式树的知识详解

笔者最近学了表达式树这一部分内容,为了加深理解,写文章巩固知识,如有错误,请评论指出~


表达式树的概念

  • 表达式树的创建有 Lambda法组装法
  • 学习表达式树需要 委托、Lambda、Func<> 基础。
  • 表达式树 形状可以参考 二叉树。

  • 可以把表达式树理解成 数学表达式。

    数学表达式的所有常量、符号为表达式树的底节点。每一次计算生成的结果是一个结点,或者说他们的共同结点就是他们应该进行的运算。


生成表达式树

表达式树的创建有 Lambda表达式法组装法

为了方便,这里指定生成的表达式为 ( i * j ) + ( x * y )

他们的运算是这样的

Lambda 生成表达式树

在控制台创建应用,需要引入

using System.Linq.Expressions;

  1,创建表达式

    (系统自动把 Lambda表达式 转为表达式树,当然,不是所有的 Lambda表达式都能转为表达式树,详细请参考文章后面的“系统自动把 Lambda表达式 转为 表达式树” 一节)

 Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);

  2,输出系统转换的表达式

    输入这一行代码后运行,看看控制台输出的表达式树

Console.WriteLine(func);

  3,把代码转为数据

    (把代码当作数据来使用)

var compile = func.Compile();
            //或 Func<int, int, int, int, int> compile = func.Compile();

  4,代入运算

            int result = compile(12, 13, 14, 15);       //把具体数字代入表达式并运算
            Console.WriteLine(result);      //输出表达式结果

完整代码如下

           Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);
            Console.WriteLine(func);        //输出表达式

            var compile = func.Compile();       //把代码转为数据
            //或 Func<int, int, int, int, int> compile = func.Compile();

            int result = compile(12, 13, 14, 15);       //把具体数字代入表达式并运算
            Console.WriteLine(result);      //输出表达式结果
            Console.ReadKey();

控制台输出

组装法生成表达式树

表达式由 "符号" 和 运算符组成,。

使用 ParameterExpression 类型 来修饰参数,使用 Expression.Parameter(Type type,string name) 实例化参数。

  1,生成 a b  d 参数

        ParameterExpression a = Expression.Parameter(typeof(int), "i");
            ParameterExpression b = Expression.Parameter(typeof(int), "j");
            ParameterExpression c = Expression.Parameter(typeof(int), "x");
            ParameterExpression d = Expression.Parameter(typeof(int), "y");

  分析:

     i、j、x、y 是结点名称,a、b、c、d 是实例名称。不用留精力思考我上面 a b c d i j x y 的名称设定。

    ParameterExpression 表示创建一个节点,Parameter 表示一个命名的参数表达式,详细请参考文章后面的 “Expression 参数分类”

    Expression.Parameter(Type type,string name) 表示这个节点的属性。

  2,生成结点

            Expression r1 = Expression.Multiply(a, b);      //乘法运行
            Expression r2 = Expression.Multiply(c, d);      //乘法运行

  分析:

    创建了 ( i * j )( x * y ) 两个运算

    Multiply 表示 不进行溢出检查的乘法运算。Expression 里有 85种 操作方法,更多加减乘除比较大小等操作在文章后面详细附上,参考 “ 运算操作符” 一节。

  3,生成终结点

Expression result = Expression.Add(r1, r2);     //相加

  4,生成表达式树、转换、输出表达式树、代入数据进行运算

            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
            var com = func.Compile();
            Console.WriteLine("表达式" + func);
            Console.WriteLine(com(12, 12, 13, 13));

完整代码如下

            ParameterExpression a = Expression.Parameter(typeof(int), "i");
            ParameterExpression b = Expression.Parameter(typeof(int), "j");

            Expression r1 = Expression.Multiply(a, b);      //乘法运行
            ParameterExpression c = Expression.Parameter(typeof(int), "x");
            ParameterExpression d = Expression.Parameter(typeof(int), "y");
            Expression r2 = Expression.Multiply(c, d);      //乘法运行

            Expression result = Expression.Add(r1, r2);     //相加
            //以上代码产生结点
            //生成表达式
            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
            var com = func.Compile();
            Console.WriteLine("表达式" + func);
            Console.WriteLine(com(12, 12, 13, 13));
            Console.ReadKey();

控制台界面


补充说明

  1,系统自动把 Lambda表达式 转为 表达式树

    对 lambda表达式 的要求 只能 由 传入参数 和 返回参数 两部分表示。lambda表达式 不能包含其它判断、循环等的代码。

      错误举例

            Expression<Func<int, int, int, int, int>> func = (a, b, c, d) =>
            {
                if (a < 10)
                {
                    a += 1;
                }
                /*
                 * 其它操作代码
                 */
                return a + b + c + d;
            };

      把那些东西通通删除,修改后:

 Expression<Func<int, int, int, int, int>> func = (a, b, c, d) => a + b + c + d;

  这样的 “最简” 的 lambda表达式 才能被系统自动转为表达式树

  2,运算操作符

     一般数学上,有加减乘除、取余、求幂等操作,而在程序中,运算操作符可以有更多的选择,达 85 种。

     笔者这里给出一张图列出部分方法。

微软官方 的操作运算符列表 https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expression?view=netframework-4.7.2

估计大家看微软的文档会有点不爽~这里推荐大神翻译、整理的列表 https://blog.csdn.net/zhuqinfeng/article/details/70168337

3,Expression 参数

以数学 椭圆周长公式:L = 2πb + 4(a-b)  ,a 为长半轴,b 为短半轴, 进行举例

Parameter 类似于 数学的 未知数 如 a 、 b;使用方法

ParameterExpression a = Expression.Parameter(typeof(int), "a")
ParameterExpression b = Expression.Parameter(typeof(int), "b")

Constant 表示一个常数,例如 2πb 中的 2 或者 2π ;使用方法

ConstantExpression define = Expression.Constant(2);

  其它更多参数分类 请查看 https://blog.csdn.net/zhuqinfeng/article/details/70168337

这里附上部分截取图片

4,Expression 的操作方法

表示加减乘除等运算的方法。以下图举例

Multiply(a,b) 为乘法,Add(r1,r2) 为加法。

当然,并没有这么简单,他们都有相关的重载方法和高级的使用用途。

请查看 https://blog.csdn.net/zhuqinfeng/article/details/70168337

这里给出部分截图

5,表达式树的高级用法

表达式树可以结合 数据库查询 或 Linq,衍生很多高级操作。

例如 动态查询、遍历表达式树、转成成 SQL where 子句等等,限于幅度,笔者不再赘述。

下面的链接可以查看 System.Linq.Expressions 的所有类型对象。https://docs.microsoft.com/zh-cn/dotnet/api/System.Linq.Expressions?view=netframework-4.7.2

好好学习,天天向上~期望 3号面试成功

原文地址:https://www.cnblogs.com/whuanle/p/10039237.html

时间: 2024-10-18 22:35:45

C# 表达式树 创建、生成、使用、lambda转成表达式树~表达式树的知识详解的相关文章

AngularJS开发指南15:AngularJS的创建服务,将服务注入到控制器,管理服务依赖详解

创建服务 虽然AngularJS提供了很多有用的服务,但是如果你要创建一个很棒的应用,你可能还是要写自己的服务.你可以通过在模块中注册一个服务工厂函数,或者通过Module#factory api或者直接通过模块配置函数中的$provide api来实现. 所有的服务都符合依赖注入的原则.它们用一个唯一的名字将自己注册进AngularJS的依赖注入系统(injector),并且声明需要提供给工厂函数的依赖.它们的依赖在测试中可以是虚拟的,这使得它们能很好地被测试. 注册服务 要注册服务,你首先要

oracle创建用户、表空间、临时表空间、分配权限步骤详解

首先登陆管理员账号,或者有DBA权限的用户,接下来依次: --查询所有用户select * from dba_users;--创建新用户create user gpmgt identified by GPMGT; --查看所有用户所在表空间select username,default_tablespace from dba_users; --查询所有表空间路径select * from dba_data_files ;--创建一个表空间create tablespace GPMGT_DATA

8天掌握EF的Code First开发系列之3 管理数据库创建,填充种子数据以及LINQ操作详解

本篇目录 管理数据库创建 管理数据库连接 管理数据库初始化 填充种子数据 LINQ to Entities详解 什么是LINQ to Entities 使用LINQ to Entities操作实体 LINQ操作 懒加载和预加载 插入数据 更新数据 删除数据 本章小结 本人的实验环境是VS 2013 Update 5,windows 10,MSSQL Server 2008. 上一篇<Code First开发系列之领域建模和管理实体关系>,我们主要介绍了EF中“约定大于配置”的概念,如何创建数据

C# Lambda表达式详解,及Lambda表达式树的创建

最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介.优雅. Lambda表达式 "Lambda表达式"是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型,支持带有可绑定到委托或表达式树的输入参数的内联表达式.所有Lambda表达式都使

通过编译lambda表达式来创建实例(可在反射时候用,效率比反射高一些)

原文地址:https://rogerjohansson.blog/2008/02/28/linq-expressions-creating-objects/ 据说编译lambda创建实例是比反射快.实际测试了一下,循环创建10,000次花的时间差不多,创建1,000,000,反射大概十几秒,lambda不到1秒. 实际使用应该没什么影响,因为一般不会出现大量创建实例的场景.不过创建生成lambda的代码还是可以学习下的. class Program { static void Main(stri

动态生成C# Lambda表达式

转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为了让代码简洁和优雅的呈现,C# Lambda表达式的使用功不可灭,那么依托外部条件如何动态构建C# Lambda表达式呢.下面让我们来具体的看看实施. 或许你会奇怪这个需求是如何产生的…… 首先,Lambda 在 DLinq 中承担了以往 T-SQL 的部分角色:其次,在数据库设计中,我们往往需要依

五分钟重温C#委托,匿名方法,Lambda,泛型委托,表达式树

五分钟重温C#委托,匿名方法,Lambda,泛型委托,表达式树 https://masuit.com/81 曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五分钟内看完这篇博客 第一分钟:委托 有些教材,博客说到委托都会提到事件,虽然事件是委托的一个实例,但是为了理解起来更简单,今天只谈委托不谈事件.先上一段代码: 下边的代码,完成了一个委托应用的演示.一个委托分三个步骤: 1 2 3 4 5 6 7 8 9 10 11 12

Lambda表达式详解【转】

前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸lambda吧:简化了匿名委托的使用,让你让代码更加简洁,优雅.据说它是微软自c#1.0后新增的最重要的功能之一. lambda简介 lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 “成为”.运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体. lambda表达式: 1.一个参数:param=>expr 2

Lambda表达式详解

前言 lambda:简化了匿名委托的使用,让你让代码更加简洁,优雅.据说它是微软自c#1.0后新增的最重要的功能之一. lambda简介 lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 “成为”.运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体. lambda表达式: 1.一个参数:param=>expr 2.多个参数:(param-list)=>expr 上面这些东西,记着,下面我们