拼吾爱程序人生.Net编程Visual Studio.NET Get a Grasp on Expression Trees

1  /  1  页   1 跳转 查看:765

Get a Grasp on Expression Trees

Get a Grasp on Expression Trees

Posted by Hartmut Wilms  From/InfoQ

Developers familiar with functional programming languages might not need an explanation as to why expression trees are useful. For the rest of us expression trees are the most striking concept of all the new features in C# 3.0 or VB 9.0.

Charlie Calvert explains the Expression Tree Basics. He starts by describing the syntax and shows how to visualize expression trees with the help of the ExpressionTreeVisualizer that ships with the Visual Studio 2008 samples.

Expression trees are related to lambda expressions, which are the logical next step in the line of delegates and anonymous delegates.  In his article on expression trees Ian Griffiths gives a great introduction to lambda expressions and their relation to expression trees. As Ian points out "lambdas don't appear to offer anything I didn't already have with anonymous methods besides a different syntax. However, they turn out to be able to do something that anonymous methods cannot":
Func<int, bool> nonExprLambda = x => (x & 1) == 0;
Expression<Func<int, bool>> exprLambda = x => (x & 1) == 0;

[...]

The second line is more interesting. This takes that Func delegate, and uses it as the type parameter for a generic type called Expression. It then proceeds to initialize it in exactly the same way, so you'd think it was doing much the same thing. But it turns out that the compiler knows about this Expression type, and behaves differently. Rather than compiling the lambda into IL that evaluates the expression, it generates IL that constructs a tree of objects representing the expression.

Charlie delves into the Expression [td]details:
There are four properties in the Expression<TDelegate> class:
  • Body: Retrieve the body of the expression.
  • Parameters: Retrieve the parameters of the lambda expression.
  • NodeType: Gets the ExpressionType for some node in the tree. This is an enumeration of 45 different values, representing all the different possible types of expression nodes, such as those that return constants, those that return parameters, those that decide whether one value is less than another (<), those that decide if one is greater than another (>), those that add values together (+), etc.
  • Type: Gets the static type of the expression. In this case, the expression is of type Func<int, int, int>.
As almost all of the new features in C# 3.0 and VB 9.0 expression trees play a key role in "LINQ, and particularly in LINQ to SQL":
var query = from c in db.Customers
            where c.City == "Nantes"
            select new { c.City, c.CompanyName };
LINQ expressions return an IQueryable. IQueryable contains an expression tree, which represents the LINQ query. At the moment the query is created, no SQL statement is issued to the database. The SQL statement is created and executed when your code iterates the IQueryable object. This concept is called deferred execution.
Charlie Calvert explains the use of this approach:
Because the query comes to the compiler encapsulated in such an abstract data structure, the compiler is free to interpret it in almost any way it wants. It is not forced to execute the query in a particular order, or in a particular way. Instead, it can analyze the expression tree, discover what you want done, and then decide how to do it. At least in theory, it has the freedom to consider any number of factors, such as the current network traffic, the load on the database, the current results sets it has available, etc. In practice LINQ to SQL does not consider all these factors, but it is free in theory to do pretty much what it wants. Furthermore, one could pass this expression tree to some custom code you write by hand which could analyze it and translate it into something very different from what is produced by LINQ to SQL.
Marlon Grech shows how to work with expression trees and create an expression parser.  A summary of the expression tree expressions class hierarchy is provided by Octavio Hernández.

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [Visual Studio.NET] 的这些文章也感兴趣:

Visual Studio2008的新功能:代码度量
Mono v1.2.51 - 开源版本的.NET框架
XNA水面效果
编程技术书籍推荐
View the .NET Source Code in VS 2005
Visual Studio International Pack 1.0扩展.NET对国际化的支持
让flex3与flash cs3珠联璧合协作开发
几乎一半.NET用户不参与开源
TFS 2008 中文版下载及安装完整图解
Microsoft Expression Blend™ 2 Service Pack 1中文版发布
 

回复: Get a Grasp on Expression Trees

译/张海龙

对于熟悉函数式编程语言的开发者而言,可能不需要再解释为什么说“表达式树(即Expression Tree)是非常有用的”,但对其他人来讲,表达式树则是C# 3.0或VB 9.0的所有新特性中最引人注目的一个概念。

Charlie Calvert讲解了表达式树的基础,他从语法描述开始,并以同Visual Studio 2008一起发行的示例程序——ExpressionTressVisualizer为例,形象地展示了如何使用表达式树。

表达式树与Lambda表达式相关联,Lambda表达式是可在行内实现预期代理和匿名代理的内容的一种方式。Ian Griffiths在他关于表达式树文章中,给出了一个非常不错的Lambda表达式介绍,以及Lambda与表达式树的关系。正如Ian所指出的,“Lambda除了语法不同以外,并没有比我已掌握的匿名方法提供更多的东西,但是,它却使一些匿名方法无法实现的事情变成了可能。”
Func<int, bool> nonExprLambda = x => (x & 1) == 0;
Expression<Func<int, bool>> exprLambda = x => (x & 1) == 0;[...]

第二行更有趣,它变成Func的代理,将Func作为一种名为Expression的泛型的类型参数,然后按照相同的方式进行初始化,因此,你可能会认为两者是在完成同样的事情,但是,它却能让编译器知道了Expression类型,这就导致了不一样的行为;前者会直接将Lambda表达式编译为IL,而后者则是通过对表达式进行评估后,生成一个可以创建并代表此表达式的对象树的IL。
Charlie仔细钻研了Expression的细节:

Expression<TDelegate>类共有四个属性:

  • Body:获取表达式的主体;
  • Parameters:获取Lambda表达示的参数;
  • NodeType:得到树中某些节点的表达式类型(ExpressionType),这是一个有45种不同值的枚举类型,代表表达式节点的所有可能类型,如返回常数、也可能返回参数、或者返回一个值是否小于另外一个(<),或者返回一个值是否大于另外一个(>),或者返回两个值的和(+)等等;
  • Type:得到表达式的静态类型,在本例中,表达式的类型是Func<int, int, int>。
在C# 3.0和VB 9.0大部分新特性中,表达式树在“LINQ,尤其是LINQ to SQL”中扮演了一个非常重要的角色:
var query = from c in db.Customers
            where c.City == "Nantes"
            select new { c.City, c.CompanyName };
LINQ表达式会返回一个IQueryable类型的值,IQueryable值包含有一个表达式树,由它来代表这个LINQ查询。当创建这个查询时,SQL语句并没有被发送到数据库中,只有当你在代码中对这个IQueryable对象进行Iterate操作时,这个SQL语句才会被创建并执行,这个概念就是延迟执行

Charlie Calvert对这种方法的使用进行了说明:

因为查询是以一种高度抽象的数据结构封装后传送给编译器的,所以,编译器可以以它期望的任一方式自由地进行翻译。查询的执行次序和途径并非强制指定的,相反,它可以对表达树进行分析,以发现你所期望的结果,然后再决定如何处理;至少在理论上,它可以独立地考虑很多因素,诸如当前的网络流量、数据库的负载、它当前已有的可用结果集等等;虽然在LINQ to SQL中,它实际上并没有去考虑所有这些因素,但在理论上它可以考虑更多它关心的因素;此外,它还可以对表达式树进行分析,并将LINQ to SQL的输出结果转换成截然不同的形式,然后传递给你手写的自定义代码。
Marlon Grech展示了如何应用表达式树,以及如何创建表达式解析器。Octavio Hernández提供了一个表达式树的表达式类层次汇总表。
 
1  /  1  页   1 跳转

快速回复帖子

标题
禁用 URL 识别
禁用表情
禁用 Discuz!NT 代码
使用个人签名
  [完成后可按 Ctrl+Enter 无刷新发布]  

版权所有 拼吾爱程序人生    Total Unique Visitors:

web counter

Powered by Discuz!NT 2.1.202   Copyright © 2001-2008 Comsenz Inc. 鄂ICP备07500843号
返顶部