C#中的表达式树的浅解
表达式树可以说是Linq的核心之一,为什么是Linq的核心之一呢?因为表达式树使得c#不再是仅仅能编译成IL,我们可以通过c#生成一个表达式树,将结果作为一个中间格式,在将其转换成目标平台上的本机语言。比如SQL。我们常用的Linq to sql就是这样生成SQL的。
表达式树是.NET 3.5之后引入的,它是一个强大灵活的工具(比如用在LINQ中构造动态查询)。
先来看看Expression类的API接口:
namespace System.Linq.Expressions
{
//
// 摘要:
// 以表达式目录树的形式将强类型 lambda 表达式表示为数据结构。此类不能被继承。
//
// 类型参数:
// TDelegate:
// System.Linq.Expressions.Expression`1 表示的委托的类型。
public sealed class Expression<TDelegate> : LambdaExpression
{
//
// 摘要:
// 将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示该 lambda 表达式的委托。
//
// 返回结果:
// 一个 TDelegate 类型的委托,它表示由 System.Linq.Expressions.Expression`1 描述的已编译的 lambda 表达式。
public TDelegate Compile();
//
// 摘要:
// 生成表示 lambda 表达式的委托。
//
// 参数:
// debugInfoGenerator:
// 编译器用于标记序列点并批注局部变量的调试信息生成器。
//
// 返回结果:
// 包含 lambda 的已编译版本的委托。
public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);
//
// 摘要:
// 创建一个与此表达式类似的新表达式,但使用所提供的子级。如果所有子级都相同,则将返回此表达式。
//
// 参数:
// body:
// 结果的 System.Linq.Expressions.LambdaExpression.Body 属性。
//
// parameters:
// 结果的 System.Linq.Expressions.LambdaExpression.Parameters 属性。
//
// 返回结果:
// 此表达式(如果未更改任何子级),或带有更新的子级的表达式。
public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);
protected internal override Expression Accept(ExpressionVisitor visitor);
}
}
表达式树的语法如下:
Expression<Func<type,returnType>> = (param) => lamdaexpresion;
例如:
Expression<Func<int, int, int>> expr = (x, y) => x+y;
我们运行以上代码,并在VS调试模似下查看这个表达式树:
可以看到表达式树主要由下面四部分组成:
1、Body 主体部分
2、Parameters 参数部分
3、NodeType 节点类型
4、Lambda表达式类型
在上述代码中,主体即为:x+y,参数为(x,y),NodeType为Lambda表达式,返回值为int
主体部分可以是表达式,但是不能包含语句。例如:我定义一个委托,Lambda表达式可以这样写
Func<int, int, int> func = (x, y) => x + y;
也可以这样写:
Func<int, int, int> func = (x, y) => { return x + y; };
但是,在表达式树种,只能用第一种写法,如果使用第二种写法编译汇报错误:无法将具有语句体的 lambda 表达式转换为表达式树。
除了上边的写法,表达式树还有可以这么写:
ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数
ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数 BinaryExpression bexp = Expression.Add(pex1, pex2);//加法 var lambdaExp = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] {pex1,pex2 });
VS调试模式下可以看到两种写法生成的表达式树是一样的
将表达式树编译成委托
LambdaExpression是从Expression派生的类型。泛型类Expression<TDelegate>是从LambdaExpression派生的,其中泛型参数TDelegate必须是委托类型。
LambdaExpression有个Compile方法能创建恰当类型的一个委托。而Expression<TDelegate>的Compile方法返回TDelegate类型的委托。来看看下面的例子:
Expression<Func<int, int, int>> expr = (x, y) => x + y; ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数
ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数 BinaryExpression bexp = Expression.Add(pex1, pex2);//主体,加法 //使用Expression.Lambda方法,创建一个委托类型已知的Expression
Expression<Func<int,int,int>> lambdaExp
= Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] { pex1, pex2 }); Func<int,int,int> tDelegate = lambdaExp.Compile();//编译成委托 Console.WriteLine(tDelegate(1, 3)); Console.Read();
我们运行上面代码,结果为:4。我们写了一大堆代码,本质上就是用表达式树计算了1+3的结果。
C#中的表达式树的浅解的更多相关文章
- ASP.NET Core中使用表达式树创建URL
当我们在ASP.NET Core中生成一个action的url会这样写: var url=_urlHelper.Action("Index", "Home"); ...
- C#中的表达式树简介
表达式树是.NET 3.5之后引入的,它是一个强大灵活的工具(比如用在LINQ中构造动态查询). 先来看看Expression类的API接口: using System.Collections.Obj ...
- Linux系统中用户组、文件权限浅解
用户组 在linux中的每个用户必须属于一个组,不能独立于组外.在Linux中每个文件有所有者.所在组.其它组的概念. [所有者] 一般为文件的创建者,谁创建了该文件,就天然的成为该文件的所有者,用& ...
- prototype.js中Function.prototype.bind方法浅解
prototype.js中的Function.prototype.bind方法: Function.prototype.bind = function() { var __method = this; ...
- C#中的Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- Expression表达式树
表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 Expression<Fun ...
- 说说lambda表达式与表达式树(未完)
Lambda表达式可以转换成为代码(委托)或者数据(表达式树).若将其赋值给委托,则Lambda表达式将转换为IL代码:如果赋值给 Expression<TDelegate>,则构造出一颗 ...
- Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- C#学习笔记(九):LINQ和表达式树
LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...
随机推荐
- MySql不支持主外键
创建表不支持主外键,能够添加外键成功,但是无法外键约束.查资料发现MySql的默认ENGINE 为MyISAM ,不支持外键,需要修改为 INNODB 修改前: Create Table CREAT ...
- Eclipse远程提交hadoop集群任务
文章概览: 1.前言 2.Eclipse查看远程hadoop集群文件 3.Eclipse提交远程hadoop集群任务 4.小结 1 前言 Hadoop高可用品台搭建完备后,参见<Hadoop ...
- MFC 创建选项卡
1.创建三个选项卡Dialog窗体,ID分别改为porpTest1.porpTest2.porpTest3 2.创建三个选项卡类,类名分别为CPropTest1.CPropTest2.CPropTes ...
- [Leetcode][016] 3Sum Closest (Java)
题目: https://leetcode.com/problems/3sum-closest/ [标签]Array; Two Pointers [个人分析] 这道题和它的姊妹题 3Sum 非常类似, ...
- 在git bush中如何退出vim编辑器
写npm的pakege.json文件的files配置时,如果有不想包含的文件,那就要创建.npmignore文件排除,但windows系统又不允许创建以点开头命名的文件,咋办? 这时候就要用到linu ...
- Katana 还是Owin ? 本地自承载
使用Owin 将Web项目脱离 IIS确实很特别..... 由此 ,可以衍生出,一个新的通信渠道,本地Server的自承载. 1 Node.js 2 Python 3 Ruby 4 Owin (C#- ...
- BZOJ2023: [Usaco2005 Nov]Ant Counting 数蚂蚁
2023: [Usaco2005 Nov]Ant Counting 数蚂蚁 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 56 Solved: 16[S ...
- MSSQL的编译和执行过程
原文地址:http://www.cncms.com.cn/mssql/3350_11.htm
- poj3708:函数式化简+高精度进制转换+同余方程组
题目大意 给定一个函数 找出满足条件 等于 k 的最小的x m,k,d已知 其中 m,k 很大需要使用高精度存储 思路: 对 函数f(m)进行化简 ,令t=ceil( log(d,m) ) 可以得 ...
- Android 读取手机某个文件夹目录及子文件夹中所有的txt文件
1. activity_main.xml文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/andro ...