C#函数式程序设计之代码即数据
自3.5版本以来,.NET以及微软的.NET语言开始支持表达式树。它们为这些语言的某个特定子集提供了eval形式的求值功能。考虑下面这个简单的Lambda表达式:
Func<int, int, int> add = (x, y) => x + y;
可以知道,上述代码最后生成一个局部函数。Lambda表达式是需要编译的代码。在C#编译器运行时,把匿名函数转换为IL代码。为了建立一个表达式树,需要对上述语法稍作修改:
Expression<Func<int, int, int>> addExpr = (x, y) => x + y;
唯一的差别是保存Lambda表达式的变量的类型。这个差别指示C#编译器生成完全不同的代码。编译器不是把表达式编译成IL代码,进行加法运算,而是自动生成一段代码,这段代码可以创建复杂的对象层级结构。对象的类型全部都是从System.Linq.Expressions.Expression派生出来的。
由于保存addExpr变量中的值是Lambda表达式的一个抽象表示,因此它不可以直接执行。但是.Net Framework可以在运行时编译一个表达式树:
Func<int, int, int> addCompiled = addExpr.Compile();
C#函数式程序设计之分析表达式
把代码看成数据这个思想的主要动理论是它允许我们在运行时分析代码。有时,这个想法的动机是了解代码的执行过程,但是,它也允许我们在运行时把代码转换为最适合于当前任务的执行格式。
表达式树使用了语法树中十分常见的一种结构。层级中包含的每个元素都派生自一个公用的基类,每个类型都需要一个派生类。同时,公用基类有一个枚举类型字段,在进行任何类型转换之前,利用这个字段进行类型检查。
在实际应用中,分析表达式树的目的是把表达式树转换为不同的格式,但是它们表示同一个或同类表达式。考虑下面这个LINQ表达式:
var peopleWithInTheirName =
from p in people
where p.Name.Contains("i")
select p;
这个简短的查询要在people集合中查找所有由Name属性返回的字符串中有i的元素。对于LINQ,C#编译器把像这个例子的查询表达式转换为一系列的方法调用,把where字句转换为Lambda表达式:
p => p.Name.Contains("i");
这个表达式接受一个对象p,然后返回针对这个对象的某个条件是否成立。这种类型的表达式被称为谓词。.NET Framework专门为这些表达式预定义了一个委托类型,即Predicate<T>:
Predicate<Person> nameContainsI = p => p.Name.Contains("i");
Predicate<T>在功能上等效于Func<T , bool>:接受类型为T的一个项为参数,返回一个bool值表示这个给定的T参数是否满足某个条件。
下面是一个用递归算法求阶乘的简单函数:
static int Fact(int x)
{
int result = 1;
for (int i = 2 ; i <= x; i++)
result *= i;
return result;
}
如果使用Lambda表达式:
Func<int, int> Fact = x =>
{
int result = 1;
for (int i = 2; i <= x; i++)
result *= i;
return result;
};
表达式树的核心是运行时处理代码——不管是需要理解和分析代码,或者动态生成代码。
C#函数式程序设计之代码即数据的更多相关文章
- C#函数式程序设计之用闭包封装数据
		
如果一个程序设计语言能够用高阶函数解决问题,则意味着数据作用域问题已十分突出.当函数可以当成参数和返回值在函数之间进行传递时,编译器利用闭包扩展变量的作用域,以保证随时能得到所需要的数据. C#函数式 ...
 - C#函数式程序设计之泛型(下)
		
C#函数式程序设计之泛型(下) 每当使用泛型类型时,可以通过where字句对泛型添加约束: + 这个例子直观地声明了一个约束:类型T必须与ListItem<string>相匹配.泛型类 ...
 - C#函数式程序设计之函数、委托和Lambda表达式
		
C#函数式程序设计之函数.委托和Lambda表达式 C#函数式程序设计之函数.委托和Lambda表达式 相信很多人都听说过函数式编程,提到函数式程序设计,脑海里涌现出来更多的是Lisp.Haske ...
 - C#函数式程序设计之惰性列表工具——迭代器
		
有效地处理数据时当今程序设计语言和框架的一个任务..NET拥有一个精心构建的集合类系统,它利用迭代器的功能实现对数据的顺序访问. 惰性枚举是一个迭代方法,其核心思想是只在需要的时候才去读取数据.这个思 ...
 - Entity Framework 程序设计入门二 对数据进行CRUD操作和查询
		
前一篇文章介绍了应用LLBL Gen生成Entity Framework所需要的类型定义,用一行代码完成数据资料的读取, <LLBL Gen + Entity Framework 程序设计入门& ...
 - C#函数式程序设计之局部套用与部分应用
		
函数式设计的核心与函数的应用以及函数如何作为算法的基本模块有关.利用局部套用技术可以把所有函数看成是函数类的成员,这些函数只有一个形参,有了局部套用,才有部分应用.部分应用是使函数模块化成为可能的两个 ...
 - 我终于理解了LISP『代码即数据|数据即代码』的含义
		
以前我一直不能理解LISP里引用的作用,感觉引用和字符串没什么区别.比如:> (define (func) 'ok) > (func) 'ok 这里把引用ok当做了函数func的返 ...
 - C#函数式程序设计之泛型
		
Intellij修改archetype Plugin配置 2014-03-16 09:26 by 破狼, 204 阅读, 0 评论,收藏, 编辑 Maven archetype plugin为我们提供 ...
 - C#函数式程序设计之泛型(上)
		
在面向对象语言中,我们可以编写一个元素为某个专用类型(可能需要为此创建一个ListElement)的List类,或者使用一个非常通用.允许添加任何类型元素的基类(在.NET中,首先想到的是System ...
 
随机推荐
- Mac OSX - 如何在bash_profile中配置全局环境变量
			
我们知道,在Linux操作系统下,配置环境变量是使用如下命令: vim /etc/profile 在OSX下,我们用如下命令打开环境变量配置文件: open ~/.bash_profile 典型的环境 ...
 - HDU  4762  Cut the Cake(公式)
			
Cut the Cake Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
 - likwid工具尝鲜
			
likwid: like I knew what I am doing. 是一系列工具的集合,用于针对多线程程序的指标分析,方便程序员进行性能调优工作.可以深入到控制cpu等硬件的频率. 主要包括以下 ...
 - memcached 源码阅读笔记
			
阅读 memcached 最好有 libevent 基础, memcached 是基于 libevent 构建起来的. 通由 libevent 提供的事件驱动机制触发 memcached 中的 IO ...
 - WordPress添加固定位置的百度分享按钮
			
第一步,在你所用主题目录新建一个名称为:share.php的模板文件,将下面的代码复制到进去并保存 <div id="share"> <div class=&qu ...
 - 在 Excel 中使用正则表达式进行查找与替换
			
在 Excel 中,使用 Alt+F11 快捷键打开 VBA 项目窗口,在左侧的工作表名称上点右键,选择查看代码,即可出出现右侧的代码编辑窗口 在代码窗口中输入以下代码: Private Sub Re ...
 - WebService SendTimeout 超时问题
			
System.TimeoutException: 请求通道在等待 00:01:00 以后答复时超时.增加传递给请求调用的超时值,或者增加绑定上的 SendTimeout 值.分配给此操作的时间可能是更 ...
 - 【Cocos2d-Js基础教学(5)资源打包工具的使用及资源的异步加载处理】
			
TexturePacker是纹理资源打包工具,支持Cocos2dx的游戏资源打包. 如果用过的同学可以直接看下面的资源的异步加载处理 首先为什么用TexturePacker? 1,节省图片资源实际大小 ...
 - [转]HTTP请求模型和头信息
			
原文链接:http://www.java3z.com/cwbwebhome/article/article2/2406.html 目录 一.连接至Web服务器 二.发送HTTP请求 三.服务端接受请求 ...
 - 聊聊 Linux 中的五种 IO 模型
			
本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451 ...