Funq之Lambda表达式2
Last month I started a series of posts covering some of the new VB and C# language features that are coming as part of the Visual Studio and .NET Framework "Orcas" release. Here are the first two posts in the series:
Today's blog post covers another fundamental new language feature: Lambda Expressions.
What are Lambda Expressions?
C# 2.0 (which shipped with VS 2005) introduced the concept of anonymous methods, which allow code blocks to be written "in-line" where delegate values are expected.
Lambda Expressions provide a more concise, functional syntax for writing anonymous methods. They end up being super useful when writing LINQ query expressions - since they provide a very compact and type-safe way to write functions that can be passed as arguments for subsequent evaluation.
Lambda Expression Example:
In my previous Extension Methods blog post, I demonstrated how you could declare a simple "Person" class like below:

I then showed how you could instantiate a List<Person> collection with values, and then use the new "Where" and "Average" extension methods provided by LINQ to return a subset of the people in the collection, as well as compute the average age of people within the collection:

The p => expressions highlighted above in red are Lambda expressions. In the sample above I'm using the first lambda to specify the filter to use when retrieving people, and the second lambda to specify the value from the Person object to use when computing the average.
Lambda Expressions Explained
The easiest way to conceptualize Lambda expressions is to think of them as ways to write concise inline methods. For example, the sample I wrote above could have been written instead using C# 2.0 anonymous methods like so:

Both anonymous methods above take a Person type as a parameter. The first anonymous method returns a boolean (indicating whether the Person's lastname is Guthrie). The second anonymous method returns an integer (returning the person's age). The lambda expressions we used earlier work the same - both expressions take a Person type as a parameter. The first lambda returns a boolean, the second lambda returns an integer.
In C# a lambda expression is syntactically written as a parameter list, followed by a => token, and then followed by the expression or statement block to execute when the expression is invoked:
params => expression
So when we wrote the lambda expression:
p => p.LastName == "Guthrie"
we were indicating that the Lambda we were defining took a parameter "p", and that the expression of code to run returns whether the p.LastName value equals "Guthrie". The fact that we named the parameter "p" is irrelevant - I could just have easily named it "o", "x", "foo" or any other name I wanted.
Unlike anonymous methods, which require parameter type declarations to be explicitly stated, Lambda expressions permit parameter types to be omitted and instead allow them to be inferred based on the usage. For example, when I wrote the lambda expression p=>p.LastName == "Guthrie", the compiler inferred that the p parameter was of type Person because the "Where" extension method was working on a generic List<Person> collection.
Lambda parameter types can be inferred at both compile-time and by the Visual Studio's intellisense engine (meaning you get full intellisense and compile-time checking when writing lambdas). For example, note when I type "p." below how Visual Studio "Orcas" provides intellisense completion because it knows "p" is of type "Person":

Note: if you want to explicitly declare the type of a parameter to a Lambda expression, you can do so by declaring the parameter type before the parameter name in the Lambda params list like so:

Advanced: Lambda Expression Trees for Framework Developers
One of the things that make Lambda expressions particularly powerful from a framework developer's perspective is that they can be compiled as either a code delegate (in the form of an IL based method) or as an expression tree object which can be used at runtime to analyze, transform or optimize the expression.
This ability to compile a Lambda expression to an expression tree object is an extremely powerful mechanism that enables a host of scenarios - including the ability to build high performance object mappers that support rich querying of data (whether from a relational database, an active directory, a web-service, etc) using a consistent query language that provides compile-time syntax checking and VS intellisense.
Lambda Expressions to Code Delegates
The "Where" extension method above is an example of compiling a Lambda expression to a code delegate (meaning it compiles down to IL that is callable in the form of a delegate). The "Where()" extension method to support filtering any IEnumerable collection like above could be implemented using the extension method code below:

The Where() extension method above is passed a filter parameter of type Func<T, bool>, which is a delegate that takes a method with a single parameter of type "T" and returns a boolean indicating whether a condition is met. When we pass a Lambda expression as an argument to this Where() extension method, the C# compiler will compile our Lambda expressions to be an IL method delegate (where the <T> type will be a Person) that our Where() method can then call to evaluate whether a given condition is met.
Lambda Expressions to Expression Trees
Compiling lambdas expressions to code delegates works great when we want to evaluate them against in-memory data like with our List collection above. But consider cases where you want to query data from a database (the code below was written using the built-in LINQ to SQL object relational mapper in "Orcas"):

Here I am retrieving a sequence of strongly typed "Product" objects from a database, and I am expressing a filter to use via a Lambda expression to a Where() extension method.
What I absolutely do not want to have happen is to retrieve all of the product rows from the database, surface them as objects within a local collection, and then run the same in-memory Where() extension method above to perform the filter. This would be hugely inefficient and not scale to large databases. Instead, I'd like the LINQ to SQL ORM to translate my Lambda filter above into a SQL expression, and perform the filter query in the remote SQL database. That way I'd only return those rows that match the query (and have a very efficient database lookup).
Framework developers can achieve this by declaring their Lambda expression arguments to be of type Expression<T> instead of Func<T>. This will cause a Lambda expression argument to be compiled as an expression tree that we can then piece apart and analyze at runtime:

Note above how I took the same p=>p.LastName == "Guthrie" Lambda expression that we used earlier, but this time assigned it to an Expression<Func<Person, bool>> variable instead of aFunc<Person,bool> datatype. Rather then generate IL, the compiler will instead assign an expression tree object that I can then use as a framework developer to analyze the Lambda expression and evaluate it however I want (for example, I could pick out the types, names and values declared in the expression).
In the case of LINQ to SQL, it can take this Lambda filter statement and translate it into standard relational SQL to execute against a database (logically a "SELECT * from Products where UnitPrice < 55").
IQueryable<T> Interface
To help framework developers build query-enabled data providers, LINQ ships with the IQueryable<T> interface. This implements the standard LINQ extension method query operators, and provides a more convenient way to implement the processing of a complex tree of expressions (for example: something like the below scenario where I'm using three different extension methods and two lambdas to retrieve 10 products from a database):

For some great blog post series that cover how to build custom LINQ enabled data providers using IQueryable<T>, please check out these great blog posts from others below:
- LINQ to Amazon: Part 1, Part 2, Part 3
- LINQ to NHibernate: Part 1, Part 2, Part 3
- LINQ to LDAP: Part 0, Part 1, Part 2, Part 3, Part 4, Part 5
Summary
Hopefully the above post provides a basic understanding of how to think about and use Lambda expressions. When combined with the built-in standard query extension methods provided in the System.Linq namespace in "Orcas", they provide a really rich way to query and interact with any type of data while preserving full compile-time checking and intellisense.
By taking advantage of the Expression Tree support provided with Lambdas, and the IQueryable<T> interface, framework developers building data providers can ensure that the clean code that developers write executes fast and efficiently against data sources (whether a database, XML file, in-memory object, web-service, LDAP system, etc).
Over the next few weeks I'll complete this language series covering the new core language concepts from a theoretical level, and then move on to cover some super practical examples of using them in action (especially using LINQ against databases and XML files).
Hope this helps,
Funq之Lambda表达式2的更多相关文章
- Funq之Lambda表达式入门
今天接受了一个Tranning关于.net3.5 framework中的new feature. 其中最不明白的还是Lambda表达式.回来后又仔细的思考了一番,总算有点体会在这里写一下.既然是入门, ...
- 你知道C#中的Lambda表达式的演化过程吗?
那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...
- Linq表达式、Lambda表达式你更喜欢哪个?
什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...
- 背后的故事之 - 快乐的Lambda表达式(一)
快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...
- Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)
作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...
- java8中lambda表达式的应用,以及一些泛型相关
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...
- 背后的故事之 - 快乐的Lambda表达式(二)
快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...
- CRL快速开发框架系列教程二(基于Lambda表达式查询)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Lambda 表达式递归用法实例
注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...
随机推荐
- Unix环境高级编程(一)
Unix基础知识1.引言2.Unix体系结构3.登陆4.文件和目录5.输入和输出6.程序和进程7.出错和处理8.用户标示9.信号10.时间值11.系统调用和库函数12.小结
- ini_set ini_get 可操作配置参数列表
为了使自己的程序在不同的平台中拥有更好的兼容性,很多时候我们都要获取当前Php的运行环境参数. 比如我们常用到的: 获取 magic_quotes_gpc 状态,来决定当表单提交时我们是否转义(add ...
- svn版本库目录结构
该文是svn源代码分析系列文章服务端架构中的一篇,主要描述svn服务端版本库数据存储目录结构,并且对这些文件以及目录的作用进行简单分析.使用“svnmadin create”命令创建初始化版本库后 ...
- Apache:怎样利用.htaccess文件对PHP站点或文件进行伪静态处理
来源:http://www.ido321.com/1123.html 今天get了一招:利用.htaccess文件对PHP站点或文件进行伪静态处理. 一.检查server是否支持伪静态处理: 必需要空 ...
- cocos2dx-3.0(前言)
说了好久,告诉自己要開始学cocos2dx(在心理里告诉了好久),然后养成良好习惯,记录自己学习cocos2dx的过程.一个是怕自己忘记.还有一个是更加让自己理解透彻(或许哪天我写的好了,组合一下出一 ...
- 如何用MathType编辑圆圈符号
数学往往是由很多的公式和符号组成的,一些用户朋友在写文章需要用到一些符号的时候,发现一般的编辑器很难满足一些比较专业的需求.这个时候就需要一款专业的数学公式编辑器.公式编辑器MathType就是这样诞 ...
- NewtonSoft.Json NULL转空字符串
from:http://www.cnblogs.com/hetuan/articles/4565702.html NewtonSoft.Json对需要转为JSON字符串的对象的NULL值以及DBNul ...
- Java StuNote 1
1. JAVA语言历史 无心插柳柳成荫,有心栽花花不开. JAVA由SUN Microsystem公司研发. 2. JAVA语言特点 a) 跨平台.一次编译.到处执行. b) 速度慢.但非常稳定, 没 ...
- 命令提示符(cmd)中的tracert命令详解
tracert也被称为Windows路由跟踪实用程序,在命令提示符(cmd)中使用tracert命令可以用于确定IP数据包访问目标时所选择的路径.本文主要探讨了tracert命令的各个功能. 工具/原 ...
- Python 基础函数
函数: 在程序设计中,函数是指用于进行某种计算的一系列语句的有名称的组合. 定义一个函数时,需要指定函数的名称并写下一系列程序语句.定义时不会执行,运行代码时,先加载进内存中,之后使用名称来调用这个函 ...