Lambda Expressions in LINQ

在第12章,我提到可以用lambda表达式定义内联的委托定义。在如下表达式中:

customer => customer.FirstName == "Donna"

左边的操作数,customer,是输入参数。右边的操作数是lambda表达式,检查客户的名字属性是否等于"Donna"。因此,对于给定的客户对象,你再检查它的名字是否为Donna。

这个lambda表达式会被传入Where方法并对在客户列表中的每一个客户执行这个比较操作。

使用扩展方法定义的查询被称为基于方法的查询(method-based queries)。虽然查询和方法的语法不同,它们的语义相同,编译器会把它们转变为相同的IL代码。你可以根据自己的喜好使用其中之一。

让我们以一个简单的查询开始,如示例13-8所示。

示例13-8:一个简单的基于方法的查询

using System;using System.Linq;
namespace SimpleLamda{class Program{static void Main(string[] args){
      string[] names = { "Jesse", "Donald", "Douglas" };var dNames = names.Where(n => n.StartsWith("D"));foreach (string foundName in dNames){Console.WriteLine("Found: " + foundName);}
     }}}Output:Found: DonaldFound: Douglas

语句names.Where是

System.Linq.Enumerable.Where(names,n=>n.StartsWith("D"));

的一个缩写。

Where是一个扩展方法,因此你可以把对象(names)作为第一个参数传入。通过包含名空间System.Linq,你可以直接对names对象调用Where而不是通过Enumerable。

其次,dNames的类型是Ienumberable<string>;我们通过关键字var来使用编译器新的功能对其进行推断(infer)。当然这样做不会损害类型安全,因为通过推断var被编译为类型Ienumerable<string>。

因此你可以把:

var dNames = names.Where(n => n.StartsWith("D"));

这行代码理解为"从集合names中找出以字母D开头的成员,然后填充到IEnumerable集合中"。

因为方法的语法和C#编译器如何处理查询更接近,值得花一些时间来看看一个更复杂的查询是如何描述的,从而增长对LINQ的理解。让我们把示例13-3翻译成一个基于方法的查询来看看它是怎样的(参见示例13-9)。

示例13-9:使用方法语法的复杂查询

namespace Programming_CSharp{// 简单客户类public class Customer{// 和示例13-1相同}
     // 客户地址类public class Address{// 和示例13-3相同}
     // 主程序public class Tester{static void Main(){List<Customer> customers = CreateCustomerList();List<Address> addresses = CreateAddressList();
               var result = customers.Join(addresses,customer => string.Format("{0} {1}", customer.FirstName,customer.LastName),address => address.Name,(customer, address) => new { Customer = customer, Address =address }).OrderBy(ca => ca.Customer.LastName).ThenByDescending(ca => ca.Address.Street);
               foreach (var ca in result){Console.WriteLine(string.Format("{0}\nAddress: {1}",ca.Customer, ca.Address));}}
        // 使用相同数据创建客户列表private static List<Customer> CreateCustomerList(){// 和示例13-3相同}

LINQ中的Lambda表达式(2)

示例13-9:使用方法语法的复杂查询(续例)

        // 使用相同数据创建客户列表private static List<Address> CreateAddressList(){// 和示例13-3相同}}}

Output:
Janet Gates
Email:   janet1@adventure-works.com
Address: 800 Interchange Blvd., Austin
Janet Gates
Email:   janet1@adventure-works.com
Address: 165 North Main, Austin
Orlando Gee
Email:   orlando0@adventure-works.com
Address: 2251 Elliot Avenue, Seattle
Keith Harris
Email:   keith0@adventure-works.com
Address: 7943 Walnut Ave, Renton
Keith Harris
Email:   keith0@adventure-works.com
Address: 3207 S Grady Way, Renton

在示例13-3中,查询使用了查询的语法:

var result =from   customer in customersjoin address in addresses onstring.Format("{0} {1}", customer.FirstName, customer.LastName)equals address.Nameorderby customer.LastName, address.Street descendingselect new { Customer = customer, Address = address.Street };

它被翻译为以下方法的语法:

var result = customers.Join(addresses,customer => string.Format("{0} {1}",customer.FirstName,customer.LastName),address => address.Name,(customer, address) => new { Customer = customer, Address = address }).OrderBy(ca => ca.Customer.LastName).ThenByDescending(ca => ca.Address.Street);

lambda表达式需要一些时间来适应。以OrderBy子句开始;你可以把它读作"通过以下方式来排序:对于每一个客户地址,获得客户的姓氏。"你把整个语句读作:"从客户开始,和地址通过以下方式连接:连接客户的名字和姓氏,获取地址的名称,对两者进行连接,然后对于每一个结果记录创建一个客户地址对象,这个对象的客户和地址由取出来的客户和地址赋值;然后首先通过每个客户的姓氏排序,再接着根据每个地址的街道名称按降序排列。"

主要的数据源即客户集合,仍然是主要的目标对象。扩展方法Join()作用于它来执行连接操作。它的第一个参数是第二个数据源地址。接下来的两个参数是每个数据源的连接条件域。最后一个参数是连接条件的结果,实际上是查询的选择子句。

查询表达式的OrderBy子句表明你想将客户姓氏按升序排列,然后将它们的街道地址按降序排列。在方法语法中必须通过使用OrderBy和ThenBy方法指明这个顺序。

也可以只调用一系列的OrderBy方法,但是这些方法必须逆序调用。也就是说你必须在查询的OrderBy序列中首先对最后一个域调用这个方法,最后才对第一个域调用这个方法。在本例中,你须要首先调用对街道的排序,然后才能调用对名称的排序:

var result = customers.Join(addresses,customer => string.Format("{0} {1}", customer.FirstName,customer.LastName),address => address.Name,(customer, address) => new { Customer = customer, Address = address }).OrderByDescending(ca => ca.Address.Street).OrderBy(ca => ca.Customer.LastName);

从结果可以看出,两个例子的输出是一样的。因此你可以根据自己的喜好选择其中一个。

提示:Ian Griffiths,地球上最聪明的C#程序员之一,(他的blog在IanG On Tap上,(http://www.interact-sw.co.uk/iangblog/)阐述了以下的观点,我也将会在第15章演示这个观点, 但是我想在这里先表明:"你可以在许多不同的源上使用完全相同的这两个语法,但是行为并不总是相同的。一个lambda表达式的意义随着传给它的函数的原型不同而不同。在这些例子中,它是委托的一个简洁的语法。但是如果你对一个SQL数据源使用相同的查询格式,lambda表达式将会被转变为另外的东西。"

所有的LINQ扩展方法--连接(Join)、选择(Select)、Where,以及其他--具有多种实现,每个实现面向不同的目标类型。这里我们学习的是在IEnumerable上操作的方法。与在IQueryable上操作的方法有微妙的不同。它们接受表达式而不是接受连接、映射、Where及其他子句的委托。这些是非常神奇的技术,使得C#源代码能够转换为相应的SQL查询。

转载于:https://www.cnblogs.com/zhcw/archive/2012/06/21/2557336.html

LINQ中的Lambda表达式相关推荐

  1. 在Linq to Entity 中使用lambda表达式来实现Left Join和Join

    1.读取用户和部门两个表的左连接: var sg = db.Users.GroupJoin(db.Departments, u => u.DepartmentId, d => d.Depa ...

  2. Python中的Lambda表达式

    Lambda表达式 (Lambda Expressions) Lambda Expressions are ideally used when we need to do something simp ...

  3. 什么是C ++ 11中的lambda表达式?

    本文翻译自:What is a lambda expression in C++11? What is a lambda expression in C++11? 什么是C ++ 11中的lambda ...

  4. C++中的Lambda表达式详解

    函数对象与Lambdas 你编写代码时,尤其是使用 STL 算法时,可能会使用函数指针和函数对象来解决问题和执行计算.函数指针和函数对象各有利弊.例如,函数指针具有最低的语法开销,但不保持范围内的状态 ...

  5. android studio lambda插件,在Android Studio中使用Lambda表达式(retrolambda)

    在Android Studio中使用Lambda表达式 要在Android Studio中使用Lambda表达式,需要借助一个gradle插件来完成. A gradle plugin for gett ...

  6. nashorn预编译_Java 8:在新的Nashorn JS引擎中编译Lambda表达式

    nashorn预编译 在最近的一篇文章中,我了解了Java 8和Scala如何实现Lambda表达式. 众所周知,Java 8不仅引入了对Javac编译器的改进,而且还引入了全新的解决方案-Nasho ...

  7. Java 8:在新的Nashorn JS引擎中编译Lambda表达式

    在最近的一篇文章中,我了解了Java 8和Scala如何实现Lambda表达式. 众所周知,Java 8不仅引入了对Javac编译器的改进,而且还引入了全新的解决方案-Nashorn. 这个新引擎旨在 ...

  8. Java 8中使用Lambda表达式的策略模式

    策略模式是" 设计模式:可重用对象的元素"书中的模式之一 . 本书所述的策略模式的意图是: 定义一系列算法,封装每个算法,并使它们可互换. 策略使算法独立于使用该算法的客户端而变化 ...

  9. 使用NetBeans Lambda支持在Java 8中使用Lambda表达式对列表进行排序

    作为JSR 335的一部分, Lambda表达式已从Java 8开始引入Java语言,这是Java语言的一个重大变化. 如果您想了解更多关于Lambda表达式以及JSR 335的信息,可以访问以下资源 ...

最新文章

  1. 在Sql2005中,向表中插入数据时遇到uniqueidentifier列,如何插入数据?
  2. 玩转Linux必备知识(四)
  3. java个人支付系统(springboot)
  4. python连接oracle的几种方式
  5. 在你迷茫时不如学好一门语言(送给大一的学弟学妹)
  6. 物联网部署的5个阶段
  7. 网络地址转换协议NAT详解
  8. 一个关于C++ Inline关键字的引发的一个错误
  9. SD-WAN、MPLS 、IPsec 和物理专线的区别
  10. 常见的域名劫持类型及如何修复
  11. 电商网站商品详情架构
  12. 一些计算两台主机之间进行socket通信的延迟的小程序
  13. 下次遇到这种游戏,这种抽奖你还点吗?
  14. 【博学谷学习记录】超强总结,用心分享 | JavaSE入门基础知识总结
  15. 基于Unity设计的井字棋小游戏
  16. 片段@厦门鼓浪屿,琴岛猫缘
  17. 配置OpenGL时遇到的一些问题
  18. FileNotFoundError: [WinError 3] 系统找不到指定的路径。: ‘/data3/eirini/datas
  19. Photoshop 快捷键
  20. 毕设 JAVAJSP超市管理系统论文

热门文章

  1. leetcode —— 513. 找树左下角的值
  2. leetcode - 1039. 多边形三角剖分的最低得分
  3. Apache HttpClient 4 3开发指南
  4. toj 4601 好老师
  5. Java中的变量分类_开发简单的Java应用
  6. ue4 运行禁用鼠标_从零开始——三:关闭电脑无用服务提高运行速度
  7. maven怎么和ecli_Maven的配置和Eclipse中导入SpringBoot项目一些注意点
  8. python print(f)执行将报错_Linux中为什么执行自己的程序要在前面加./
  9. java list 交集_java两个List的交集,并集
  10. PHP群发300万,mysql 300万数据查询500多秒如何优化