不能不说的C#特性-表达式树

2008-09-18 00:00 by 横刀天笑, 17112 阅读, 14 评论, 收藏编辑

最近发生了很多很多事情,频繁的搬家。工作上的事情也挺多的,所以博客更新的非常缓慢。

已经有很多很多人聊过这个话题,今天我在这里重复也不会探讨出什么新东西,只是把自己的理解描述出来,更是为了整个系列文章的完整性。

当你听说Linq给你的承诺时,你怎么想的?Wow,我们可以以统一的方式操作各种各样的数据了。这就是我当时的想法。虽然人们在现实中总是喜欢差异,认为差异才能产生美,如果一切的一切都是一样的,这个世界将无比的单调,可是作为程序员的我们却对标准趋之若鹜,对差异嫉恶如仇。看同桌的你是不是正在为了Oracle和Sql Server两种数据库编写两套数据访问的类?

表达式树概念

Linq的承诺貌似Java那个梦想一样:Write Once,Run Anywhere。Java是怎么做到的?Sun等公司为我们在各种平台架构上实现了各自的虚拟机,Java的编译分为两个阶段,第一阶段将Java代码编译为字节码,在这个阶段不管在什么平台上,只要Java源代码一样生成的字节码是一致的,第二个阶段,也就是运行阶段,虚拟机会根据平台的不同生成不同的代码。就是通过将编译器分为前端和后端来实现这个梦想。

实际上LINQ也是这么做的,对各种数据的操作无非“增删查改”,但是具体做的时候关系数据库需要使用SQL来操作,而XML需要XPath来操作。我们如何将“增删查改”的语法做到一致,让我们用起来好像操作的数据只有一种?

答案是使用表达式树

表达式树仅仅是将表达式(这里特指Lambda表达式)用树状的数据结构来表示。相当于Java的字节码,至于如何去解析这个树的结构那就看你自己了,如何去解释这个表达式树。

看下面这个Lambda表达式:

username => username == “yuyi”

我们主要看表达式的主体:username == “yuyi”,如果我们是要对数据库进行操作,这将翻译为字段username中所有值为”yuyi”的行,如果操作的是XML那也许是查询名称为username,值为”yuyi”的attribute。表达式树承载的只是这样一个结构:

如何解释它这是你的事。

在C#中Expression<Function<string,bool>> IsTrue = username=>username==”yuyi”,就表示一个表达式树,这个语句在编译后就组成为一个树状的结构。

在编译原理中,我们知道编译器的前两个阶段主要做的是:词法分析、语法分析。在词法分析中编译器会从代码文件中读入一个个的字符,然后识别出其中的关键字、标识符、运算符、常量、字符串等。

比如上面的表达式就会识别出:

Username->标识符

==->运算符

“yuyi”->字符串

这些东西就叫做符号

然后以这些符号作为输入进行语法分析,语法分析会将这些符号组合成一个树,这个树我们称之为抽象语法树(AST),表达式树也是一种简单的AST。

(在VS2008带的例子中有个DynamicQuery的例子,这里有一个Dynamic.cs文件,这里就自己做表达式的解析,只不过解析的是用字符串形式的表达式,通过这个代码你可以看看表达式的解析过程,这里有一个ExpressionParser类,它就是负责表达式的词法解析的,该类里有一个Token的机构,这就是上面所说的符号,TokenId表示符号的类型

<"Samples"1033"CSharpSamples"LinqSamples"DynamicQuery>)

对于Lambda表达式,有两种编译方式,常规的:

Func<string,bool> IsTrue = username => username == “yuyi”;

这个时候编译器会将其编译为匿名方法,关于匿名方法的相关介绍可以参看我这篇文章

编译成表达式树:

Expression<Func<string,bool>> IsTrue = username => username == “yuyi”;

这么细微的差别,C#这次却不真的编译这条语句,而是将其进行词法、语法分析,得到的是一个数据结构。

我们注意到表达式树还有一个Compile实例方法,它可以将表达式编译成匿名方法,也就是这个数据结构可以向匿名方法转变。

想想Linq to SQL,实际上它不就是C#作为源语言,SQL作为目标语言的一个编译过程么。形成表达式树(抽象语法树)后,就是代码生成了,只不过这个代码生成有的时候是生成代码,比如Linq to SQL,生成的是SQL语句,有的时候是生成的方法调用,比如Linq to XML,生成的是对XML文档的操作。

为什么一样的语句,有的时候是操作内存中的对象集合,有的时候是操作远程数据库?请查看我这篇文章

关于表达式树更多细节内容,你可以查看TerryLee老大的这篇图文并茂的文章

不能不说的C#特性-表达式树的更多相关文章

  1. 转载:C#特性-表达式树

    原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...

  2. C#特性-表达式树

    表达式树ExpressionTree   表达式树基础 转载需注明出处:http://www.cnblogs.com/tianfan/ 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希 ...

  3. C#学习笔记(九):LINQ和表达式树

    LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...

  4. C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

  5. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  6. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  7. [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用

    [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...

  8. C#中的Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  9. LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树

    序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...

随机推荐

  1. Android ViewPager+HorizontalScrollView实现标题栏滑动(腾讯新闻)

    1) ViewPager提供了左右滑动切换页面的方法,但是它所提供的标题只是无语,估计没有真正的项目会照搬拿过来;并且它只能一页一页滑,我想直接查看最后一页要滑半天; 2) 看了腾讯新闻客户端感觉体验 ...

  2. 通过机智云APP来学习安卓

    效果非常之好,安卓6.0之后就进行了动态授权.按照网上的视频一步一步调试的非常成功,非常舒服.

  3. Scrapy框架 之某网站产品采集案例

    一.创建项目 第一步:scrapy startproject boyuan 第二步:cd boyuan scrapy genspider product -t crawl  boyuan.com 如图 ...

  4. 网络编程 - 简单的socket例子

    1.客户端 #客户端import socketclient=socket.socket() #生成socket连接对象client.connect(("localhost",696 ...

  5. Python 爬虫爬取今日头条街拍上的图片

    # 今日头条--街拍 import requests from urllib.parse import urlencode import os from hashlib import md5 from ...

  6. NAT、NAPT(PAT)的基本概念和工作原理及区别

    转自:http://blog.sina.com.cn/s/blog_5d302bd20100gprv.html 近年来,随着 Internet 的迅猛发展,连入 Internet 的主机数量成倍增长. ...

  7. xmpp消息回执(6)

    原始地址:XMPPFrameWork IOS 开发(七)消息回执 请参考:XEP-0184协议 协议内容: 发送消息时附加回执请求 <message from='northumberland@s ...

  8. How To:分析ORACLE监听日志中的IP信息

    有时候需要分析出ORACLE日志监听中的IP信息,分享一个组合命令,Linux的shell下运行正常. grep "HOST=.*establish.*\* 0" listener ...

  9. 低版本ie兼容问题的解决方案

    CSS hack \9    所有的IE10及之前 *     IE7以及IE7以下版本的 _     IE6以及IE6以下版本的      !important  提升样式优先级权重 1.ie6,7 ...

  10. str类型内置方法

    目录 str类型内置方法 用途 定义方式 常用操作和内置方法 优先掌握 需要掌握 了解 存一个值or多个值 有序or无序 可变or不可变 强化训练 str类型内置方法 用途 字符串数字.字母.下划线组 ...