自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#函数式程序设计之代码即数据的更多相关文章

  1. C#函数式程序设计之用闭包封装数据

    如果一个程序设计语言能够用高阶函数解决问题,则意味着数据作用域问题已十分突出.当函数可以当成参数和返回值在函数之间进行传递时,编译器利用闭包扩展变量的作用域,以保证随时能得到所需要的数据. C#函数式 ...

  2. C#函数式程序设计之泛型(下)

    C#函数式程序设计之泛型(下)   每当使用泛型类型时,可以通过where字句对泛型添加约束: + 这个例子直观地声明了一个约束:类型T必须与ListItem<string>相匹配.泛型类 ...

  3. C#函数式程序设计之函数、委托和Lambda表达式

    C#函数式程序设计之函数.委托和Lambda表达式 C#函数式程序设计之函数.委托和Lambda表达式   相信很多人都听说过函数式编程,提到函数式程序设计,脑海里涌现出来更多的是Lisp.Haske ...

  4. C#函数式程序设计之惰性列表工具——迭代器

    有效地处理数据时当今程序设计语言和框架的一个任务..NET拥有一个精心构建的集合类系统,它利用迭代器的功能实现对数据的顺序访问. 惰性枚举是一个迭代方法,其核心思想是只在需要的时候才去读取数据.这个思 ...

  5. Entity Framework 程序设计入门二 对数据进行CRUD操作和查询

    前一篇文章介绍了应用LLBL Gen生成Entity Framework所需要的类型定义,用一行代码完成数据资料的读取, <LLBL Gen + Entity Framework 程序设计入门& ...

  6. C#函数式程序设计之局部套用与部分应用

    函数式设计的核心与函数的应用以及函数如何作为算法的基本模块有关.利用局部套用技术可以把所有函数看成是函数类的成员,这些函数只有一个形参,有了局部套用,才有部分应用.部分应用是使函数模块化成为可能的两个 ...

  7. 我终于理解了LISP『代码即数据|数据即代码』的含义

    以前我一直不能理解LISP里引用的作用,感觉引用和字符串没什么区别.比如:> (define (func)     'ok) > (func) 'ok 这里把引用ok当做了函数func的返 ...

  8. C#函数式程序设计之泛型

    Intellij修改archetype Plugin配置 2014-03-16 09:26 by 破狼, 204 阅读, 0 评论,收藏, 编辑 Maven archetype plugin为我们提供 ...

  9. C#函数式程序设计之泛型(上)

    在面向对象语言中,我们可以编写一个元素为某个专用类型(可能需要为此创建一个ListElement)的List类,或者使用一个非常通用.允许添加任何类型元素的基类(在.NET中,首先想到的是System ...

随机推荐

  1. latextools \cite 自动补全

    最近在用latex写毕业论文,编辑环境用的是Sublime Text 2 加 latextools 插件,在使用latextools的\cite命令来引用参考文献时,我们希望输入\cite{ 后自动弹 ...

  2. [转] Linux学习之CentOS(三十六)--FTP服务原理及vsfptd的安装、配置

    本篇随笔将讲解FTP服务的原理以及vsfptd这个最常用的FTP服务程序的安装与配置... 一.FTP服务原理 FTP(File Transfer Protocol)是一个非常古老并且应用十分广泛的文 ...

  3. C#排序比较

    与C#定义了相等性比较规范一样,C#也定义了排序比较规范,以确定一个对象与另一个对象的先后顺序.排序规范如下 IComparable接口(包括IComparable接口和IComparable< ...

  4. iOS开发——高级技术精选&底层开发之越狱开发第一篇

    底层开发之越狱开发第一篇 做越狱开发也有一些时间了,有很多东西想总结一下,希望给他人一些借鉴,也是自己对过去开发经历的一些总结.个人不推荐使用盗版,这里主要以技术介绍为主. 这个系列里面主要介绍怎样进 ...

  5. ux.form.field.SearchField 列表、树形菜单查询扩展

    //支持bind绑定store //列表搜索扩展,支持本地查询 //支持树形菜单本地一级菜单查询 Ext.define('ux.form.field.SearchField', { extend: ' ...

  6. 彻底理解JAVA动态代理

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 代理模式的结构如下图所示. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public ...

  7. Java程序性能优化Tip

    本博客是阅读<java time and space performance tips>这本小书后整理的读书笔记性质博客,增加了几个测试代码,代码可以在此下载:java时空间性能优化测试代 ...

  8. EDM博主笔记:EDM邮件营销的几个细节问题

    其实说起EDM邮件营销很多做过的人都知道,目前国内邮件营销的效果其实是比较差的,为什么?因为国内没有多少使用邮件的习惯,如果不是工作所需估计很多的人都几天不碰邮件了,但是反观国外 邮件是其日常的一部分 ...

  9. 在自己的对象里实现IEnumerator和IEnumerable

    平时工作中我们经常用foreach来迭代一个集合.比如 foreach (Student student in myClass) { Console.WriteLine(student); } 基本所 ...

  10. 在自己的框架中引用 PHPExcel

    如果直接在框架中的controller中直接引用 xxxx/PHPExcel.php,由于框架中有autoload 与PHPExcel的autoload冲突(加载目录原因), 那么在不想做太多修改的情 ...