lambda表达式和表达式树(深入理解c#)
1.Lambda形式
1). Lambda表达式最冗长的形式:
(显式类型的参数列表)=>{语句}
2). 大多数时候,都可以用一个表达式来表示主体,该表达式的值是Lambda的结果,在这些情况下,可以指定那个表达式,不使用大括号,不使用return语句,也不添加分号。
(显式类型的参数列表)=> 表达式
3). 编译器大多时候都能猜出参数类型,不需要你显式声明他们(隐式类型的参数列表就是一个以逗号分隔的名称列表,没有类型,但隐式和显式类型的参数不能混合匹配——要么全是隐式的,要么全是显式的)
(隐式类型的参数列表) => 表达式
4). 如果Lambda表达式只需一个参数,而且那个参数可以隐式指定类型,c#3允许省略圆括号。
参数名 => 表达式
2. 高阶函数
Lambda表达式的主体本身可以包含另一个Lambda表达式,但做起来就像听起来一样,很容易让人混淆,另外,Lambda表达式的参数可以是另一个委托,这样做同样很乱。
3. 表达式树
.Net3.5的表达式树提供了一种抽象方式将一些代码表示成一个对象树,c#3对于将Lambda表达式转换成表达式树提供了内建的支持。顾名思义,它们是对象构成的树,树中的每个节点本身就是一个表达式,不同的表达式类型代表能在代码中执行的不同操作。
System.Linq。Expressions命名空间包含了代表表达式的各个类,它们都继承自Expession,一个抽象的主要包含一些静态工厂方法的类,这些方法用于创建其他表达式类的实例。然而Expression也包括两个属性
1)Type属性代表表达式求值后的.Net类型,可把他视为一个返回了类型,例如,如果一个表达式要获取一个字符串的Length属性,该表达式的类型就是int。
2)NodeType属性返回所代表的表达式的种类。他是ExpessionType枚举的成员,包括LessThan,Multiply和Invoke等。仍然使用上面的例子,对于myString.Length这个属性访问来说,其节点类型是MemberAccess。该属性最重要的地方,是它能区分由相同的类表示不同种类的表达式。
4. 将表达式树编译成委托
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的结果。
5. 将c#Lambda表达式转换成表达式树
可以要求编译器通过你的Lambda表达式构建一个表达式树,在执行时创建Expression<TDelegate>的一个实例。
Expression<Func<int>> return5 = () => 5
限制:
并非所有Lambda表达式都能转换成表达式树。不能将带有一个语句块(即使只有一个return语句)的Lambda转换成表达式树——只对单个表达式进行求值的Lambda表达式才可以。表达式中还不能包含赋值操作,因为在表达式树中表示不了这种操作。尽管.Net4扩展了表达式树的功能,但只能转换单一表达式这一限制仍然有效。(上述只是最常见的,还有很多)
代码:
MethodInfo method = typeof(string).GetMethod("StartsWith", new[] {typeof(string) });
var target = Expression.Parameter( typeof(string) , "x");
var methodArg = Expression.Parameter( typeof(string) , "y");
Expression[] methodArgs = new[] {methodArg};
Expression call = Expression.Call( target,method,methodArgs);
var lambdaParamethers = new[] { target,methodArg};
var lambda = Expression.Lambda<Func<string,string,bool>>(call,lambdaParameters);
var compiled = lambda.Compile();
Console.WriteLine( compiled("First","Second" ));
Console.WriteLine( compiled("First","Fir" ));
Lambda表达式提供了编译时检查的能力,而表达式树可以将执行模型从你所需的逻辑中提取出来,提供了远程执行代码的能力。
在讨论动态类型时,将看到更多关于动态语言运行时的内容。表达式树是其架构的核心部分,他们具有三个特点对DIR特别有吸引力:
1)他们是不易变的,因此可以安全地储存;
2)他们是可组合的,因此可以在简单的块中构建出复杂的行为;
3)他们可以编译为委托,后者可以像平常那样进一步JIT编译为本地代码。
DLR需要对如何处理不同的表达式做出决定,这些表达式会因不同的规则而发生变化。表达式树允许将这些规则(和结果)转换为代码,这与你知道所有的规则和结果后,手工编写代码非常接近。这一概念异常强大,可以使动态代码以惊人的速度执行。
lambda表达式和表达式树(深入理解c#)的更多相关文章
- 16.C#初见Lambda表达式及表达式树(九章9.1-9.3)
在说明Lambda相关知识前,我们需要了解Lambda表达式常用于LINQ,那么我们来聊下LINQ. LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态.这些操作表示了各种关于数据的逻辑: ...
- C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)
Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...
- C# 表达式树 创建、生成、使用、lambda转成表达式树~表达式树的知识详解
笔者最近学了表达式树这一部分内容,为了加深理解,写文章巩固知识,如有错误,请评论指出~ 表达式树的概念 表达式树的创建有 Lambda法 和 组装法. 学习表达式树需要 委托.Lambda.Func& ...
- C#中的Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types
匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
- 无法将具有语句体的lambda表达式转换为表达式树
很早就碰到了这个问题,当时也没有深入的研究,趁着空闲,遂把这个问题研究清楚. (一)普通案例 下面从一个普通的案例入手,下面准备两个List集合,都是放在内存里面的(需要模拟到远端执行的时候,我们是通 ...
- [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门
[.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...
- [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用
[.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...
随机推荐
- 弹出序列(python)
题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压 ...
- DHCP server 冒充及DOS攻击处理方案
一.DHCP服务器在运维上存在的常见问题: 1. DHCP服务器冒充 在DHCP服务器和客户端之间没有认证机制,如果在DHCP server覆盖的网络上随意接入一个DHCP server,就有可能造成 ...
- 151. Reverse Words in a String (String)
思路: 本题考查的目的并不是使用字符串的函数.方法是两次reverse,先对每个单词先做一次翻转,然后对整个字符串做一次翻转. 需要注意的是去除extra space,并且对全space字符串.以及最 ...
- 20. Valid Parentheses (Stack)
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...
- 190. Reverse Bits (Int; Bit)
Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...
- http://ctf.bugku.com/challenges#%E6%B8%B8%E6%88%8F%E8%BF%87%E5%85%B3--游戏过关
做成功这道逆向题了,哈哈哈哈. 启程. 运行了一下子程序,发现它是要保证所有灯亮着才会给flag.如下图所示. 我聪明滴认为首先可以通过关键字符串找到关键代码位置哦. 1.找到关键代码 ...
- jQuery之禁止Get请求缓存
如果两次Get请求的URL完全一样,则IE浏览器会调用上次缓存的结果,不会发起新的Http请求. 解决办法:在URL最后面加上时间戳. jQuery全局设置禁止缓存 $.ajaxSetup({ cac ...
- swift - 使用系统app导航
import UIKit //1.导入框架 import MapKit class ViewController: UIViewController { lazy var geoCoder : CLG ...
- day 21 封装,多态,类的其他属性
封装 封装:将一些数据,重要的信息等等放到一个地方(空间中) class A: country = 'China' area = '深圳' def __init__(self,name,age): s ...
- Bootstrap(4) 表单和图片
1.表单 基本格式,实现基本的表单样式 <form class="form-horizontal"> <div class="form-group&qu ...