15.1 查询表达式的概念


简单的查询表达式

  1. private static void ShowContextualKeywords1()

  2. {

  3. IEnumerable<string> selection = from word in Keywords

  4. where !word.Contains('*')

  5. select word;

  6. foreach (string keyword in selection)

  7. {

  8. Console.Write(" " + keyword);

  9. }

  10. }

  11. private static string[] Keywords = {

  12. "abstract", "add*", "alias*", "as", "ascending*", "base",

  13. "bool", "break", "by*", "byte", "case", "catch", "char",

  14. "checked", "class", "const", "continue", "decimal",

  15. "default", "delegate", "descending*", "do", "double",

  16. "dynamic*", "else", "enum", "event", "equals*",

  17. "explicit", "extern", "false", "finally", "fixed",

  18. "from*", "float", "for", "foreach", "get*", "global*",

  19. "group*", "goto", "if", "implicit", "in", "int",

  20. "into*", "interface", "internal", "is", "lock", "long",

  21. "join*", "let*", "namespace", "new", "null", "object",

  22. "on*", "operator", "orderby*", "out", "override",

  23. "params", "partial*", "private", "protected", "public",

  24. "readonly", "ref", "remove*", "return", "sbyte", "sealed",

  25. "select*", "set*", "short", "sizeof", "stackalloc",

  26. "static", "string", "struct", "switch", "this", "throw",

  27. "true", "try", "typeof", "uint", "ulong", "unchecked",

  28. "unsafe", "ushort", "using", "value*", "var*", "virtual",

  29. "void", "volatile", "where*", "while", "yield*"

  30. };


15.1.1 投射

查询表达式输出是一个 IEnumerbale<T>或 IQueryable<T>集合。T数据类型是从select或者groupby子句推导。
上例string数据类型是从 select word推导的,因为word是一个字符串。word数据类型是由from子句所指定的IEnumerbale<T>集合的类型参数(这里是Keywords)。由于Keywords是一个string数组,它实现了IEnumerbale<T>,所以word是一个字符串。
表达式查询特定类型集合时,结果允许将数据投射成一个完全不同的类型。
Directory.GetCurrentDirectory()  


  1. public static void Main()

  2. {

  3. List1(Directory.GetCurrentDirectory(),"*");

  4. }

  5. static void List1(string rootDirectory, string searchPattern)

  6. {

  7. IEnumerable<FileInfo> files =

  8. from fileName in Directory.GetFiles(

  9. rootDirectory, searchPattern)

  10. select new FileInfo(fileName);

  11. foreach (FileInfo file in files)

  12. {

  13. Console.WriteLine(".{0} ({1})",

  14. file.Name, file.LastWriteTime);

  15. }

  16. }

 

 这里返回的是一个IEnumerable<FileInfo>,而不是System.IO.Directory.GetFiles()返回的IEnumerables<string>数据类型。
 
C#3.0引入匿名类型,很大程度上就是利用像这样的“投射”功能。
  1. var files =

  2. from fileName in Directory.GetFiles(

  3. rootDirectory, searchPattern)

  4. select new FileInfo(fileName);



15.1.2 筛选

where子句在垂直方向筛选集合。
  1. IEnumerable<string> selection = from word in Keywords

  2. where !word.Contains('*')

  3. select word;



15.1.3 排序

在查询表达式中对数据进行排序的是 orderby 子句。
  1. IEnumerable<string> fileNames =

  2. from fileName in Directory.GetFiles(

  3. rootDirectory, searchPattern)

  4. orderby (new FileInfo(fileName)).Length descending,

  5. fileName

  6. select fileName;


ascending和descending是上下文关键字,分别是升序或降序排序。


15.1.4 let子句

下面代码与上面的代码相似。问题是FileInfo要创建两次,分别在orderby 和 select子句中创建。
  1. public static void Main()

  2. {

  3. ListByFileSize2(Directory.GetCurrentDirectory(), "*");

  4. }

  5. static void ListByFileSize2(

  6. string rootDirectory, string searchPattern)

  7. {

  8. IEnumerable<FileInfo> files =

  9. from fileName in Directory.GetFiles(

  10. rootDirectory, searchPattern)

  11. orderby new FileInfo(fileName).Length, fileName

  12. select new FileInfo(fileName);

  13. foreach (FileInfo file in files)

  14. {

  15. //  As simplification, current directory is

  16. //  assumed to be a subdirectory of

  17. //  rootDirectory

  18. string relativePath = file.FullName.Substring(

  19. Environment.CurrentDirectory.Length);

  20. Console.WriteLine(".{0}({1})",

  21. relativePath, file.Length);

  22. }

  23. }


可以用let子句避免这种昂贵的开销。
  1. IEnumerable<FileInfo> files =

  2. from fileName in Directory.GetFiles(

  3. rootDirectory, searchPattern)

  4. let file = new FileInfo(fileName)

  5. orderby file.Length, fileName

  6. select file;


let 解释
  1. let子句引入了一个新的范围变量

  2. 它容纳的表达式值可以在查询表达式剩余部分使用

  3. 可以添加任意数量的let表达式,只需要它们每一个作为一个附加的子句

  4. 放在第一个from子句之后,最后一个select/group by子句之前,加入查询即可



15.1.5 分组

SQL中涉及对数据项进行聚合以生成一个汇总或合计或其他聚合值。
LINQ中表达力更强,LINQ允许将单独的项分组到一系列子集合中,还允许那些组与所查的集合中项关联
  1. private static void GroupKeywords1()

  2. {

  3. IEnumerable<IGrouping<bool, string>> selection =

  4. from word in keyWords

  5. group word by word.Contains('*');

  6. foreach (IGrouping<bool, string> wordGroup

  7. in selection)

  8. {

  9. Console.WriteLine(Environment.NewLine + "{0}:",

  10. wordGroup.Key ?

  11. "Contextual Keywords" : "Keywords");

  12. foreach (string keyword in wordGroup)

  13. {

  14. Console.Write(" " +

  15. (wordGroup.Key ?

  16. keyword.Replace("*", null) : keyword));

  17. }

  18. }

  19. }



结果


 查询结果是一系列IGrouping<bool, string>类型元素。
 
查询生成一系列分组,将相同的bool类型键应用于组内的每个string。


在group子句后面选择一个匿名类型
  1. private static void GroupKeywords1()

  2. {

  3. IEnumerable<IGrouping<bool, string>> keywordGroups =

  4. from word in keyWords

  5. group word by word.Contains('*');

  6. var selection = from groups in keywordGroups

  7. select new

  8. {

  9. IsContextualKeyword = groups.Key,

  10. Items = groups

  11. };

  12. foreach (var wordGroup in selection)

  13. {

  14. Console.WriteLine(Environment.NewLine + "{0}:",

  15. wordGroup.IsContextualKeyword ?

  16. "Contextual Keywords" : "Keywords");

  17. foreach (var keyword in wordGroup.Items)

  18. {

  19. Console.Write(" " +

  20. keyword.Replace("*", null));

  21. }

  22. }

  23. }


 IGrouping<TKey,TElement>.Key 重命名为IsContextualKeyword,并命名了子集合属性Items。有人人为可以在匿名类型中添加一个属性来标识数据项的个数,然后,这个功能由wordGroup.Items.Count()提供。


15.1.6 使用into进行查询延续

上面的代码,一个现有的查询可以作为另一个查询的输入。然而,我们可以使用into通过查询延续子句来扩展任何查询。查询延续是一个语法糖,能简单的表示“创建量个查询并将第一个用作第二个的入口”。
  1. var selection =

  2. from word in keyWords

  3. group word by word.Contains('*')

  4. into groups

  5. select new

  6. {

  7. IsContextualKeyword = groups.Key,

  8. Items = groups

  9. };


into相当于一个管道操作符,它将第一个查询结果“管道传送”给第二个查询。用这种方式可以链接起任意数量的查询。


15.1.7 用多个from 子句“平整”序列的序列

经常将一个序列的序列“平整”成单个序列。一系列客户中的每个客户都可能关联一系列订单,或者一系列目录中的每个目录都关联了一系列文件。SelectMany序列操作符(14章讨论过)可以连接所有的子序列;要用查询表达式做相同的事情,可以用多个from子句
  1. var selection = from word in keyWords

  2. from character in word

  3. select character;



 还可以用多个from子句生成笛卡尔积——几个序列所有可能的组合。
  1. var numbers = new[] {1, 2, 3};

  2. var product = from word in keyWords

  3. from number in numbers

  4. select new {word, number};


 

主题:不重复的成员

查询表达式没与专门的语法,但是,可以结合查询操作符Distict()来实现。
 typeof(Enumerable).GetMembers()返回System.Linq.Enumerable的所有成员(方法、属性等)的一个列表。但许多成员都是重载。

15.2 查询表达式作为方法调用

查询表达式未对CLR或CIL语言进行任何改动。由C#编译器将查询表达式转换成一系列方法调用。
  1. IEnumerable<string> selection = from word in Keywords

  2. where !word.Contains('*')

  3. select word;


编译之后,会转换成一个由System.Linq.Enumerable提供的IEnumerable<T>扩展方法调用
  1. IEnumerable<string> selection =

  2. keyWords.Where(word => word.Contains('*'));


如14章所述,Lambda表达式随后由编译器转换成一个带有Lambda的主体的方法。Lambda表达式的作用变成分配一个对该方法的委托。        
每个查询表达式都能转换成方法调用,但不是每一系列的方法调用都有对应的查询表达式。例如,扩展方法TakeWhile<T>(Func<T,bool> predicate)就没有与之等价的查询表达式,这个扩展方法只要谓词返回true,就反复返回集合中的项。


《C#本质论》读书笔记(15)使用查询表达式的LINQ的更多相关文章

  1. C#复习笔记(4)--C#3:革新写代码的方式(查询表达式和LINQ to object(下))

    查询表达式和LINQ to object(下) 接下来我们要研究的大部分都会涉及到透明标识符 let子句和透明标识符 let子句不过是引入了一个新的范围变量.他的值是基于其他范围变量的.let 标识符 ...

  2. 十五、C# 使用查询表达式的LINQ

    使用查询表达式的LINQ   本章介绍了一种新的语法,查询表达式.   1.查询表达式概述 2.特点:投射  筛选  排序   Let  分组 3.作为方法调用   标准查询运算符所实现的查询在功能上 ...

  3. 查询表达式和LINQ to Objects

    查询表达式实际上是由编译器“预处理”为“普通”的C#代码,接着以完全普通的方式进行编译.这种巧妙的发式将查询集合到了语言中,而无须把语义改得乱七八糟 LINQ的介绍 LINQ中的基础概念 降低两种数据 ...

  4. 『TCP/IP详解——卷一:协议』读书笔记——15

    2013-08-25 13:39:40 第6章 ICMP:Internet控制报文协议 6.1 引言 ICMP经常被认为是IP层的一个组成部分.它传递差错报文以及其他需要注意的信息.ICMP报文同通常 ...

  5. Microsoft SqlServer2008技术内幕:T-Sql语言基础-读书笔记-单表查询SELECT语句元素

    1.select语句逻辑处理顺序: FORM WHERE GROUP BY HAVING SELECT OVER DISTINCT TOP ORDER BY 总结: 2.FORM子句的表名称应该带上数 ...

  6. C#本质论读书笔记:第一章 C#概述|第二章 数据类型

    第一章 1.字符串是不可变的:所有string类型的数据,都不可变,也可以说是不可修改的,不能修改变量最初引用的数据,只能对其重新赋值,让其指向内存中的一个新位置. 第二章 2.1 预定义类型或基本类 ...

  7. Java SE 8 for the Really Impatient读书笔记——Java 8 Lambda表达式

    1. lambda表达式的语法 lambda表达式是一种没有名字的函数,它拥有函数体和参数. lambda表达式的语法十分简单:参数->主体.通过->来分离参数和主体. 1.1 参数 la ...

  8. Http读书笔记1-5章

    第一章 内容提要 这一章主要介绍了什么是http以及http是干嘛的,以及与之有关的相关概念,当然了这些概念都是概览式的介绍一些.所以我将采用问答式的方式描述这一章! Q:http是干嘛的? A:ht ...

  9. SQL.Cookbook 读书笔记5 元数据查询

    第五章 元数据查询 查询数据库本身信息 表结构 索引等 5.1 查询test库下的所有表信息 MYSQL SELECT * from information_schema.`TABLES` WHERE ...

随机推荐

  1. Python-urlparse

    如何把get请求的参数转成字典 (Map) urlparse.parse_qs(params) //str 需要转成字典的 请求参数 //{'phone': ['075988888888'], 'id ...

  2. 美化radio和checkbox样式

    HTML部分 <div id="holder"> <div> <div class="tag">Checkbox Small ...

  3. nginx 报错 HTTP ERROR 500 (PHP数组简写模式)

    同样的代码放在Apache上执行可以执行,在nginx上面就报错了. 百度出来一堆结果貌似都不对,然后只有注释代码->运行程序,一步步找到问题所在 $buffer = []; 这一步报错了 原来 ...

  4. 【bzoj3505】 Cqoi2014—数三角形

    http://www.lydsy.com/JudgeOnline/problem.php?id=3505 (题目链接) 题意 给定一个n*m的网格,请计算三点都在格点上的三角形共有多少个. Solut ...

  5. sql语法:inner join on, left join on, right join on详细使用方法

    inner join(等值连接) 只返回两个表中联结字段相等的行 left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有 ...

  6. Android Studio中JNI程序的单步调试和日志打印

    近日有个算法(检测碰撞)需要用C++实现,目的是IOS和ANDROID中共享同一段程序. 下面说说android调用这段程序过程中遇到的一些事情.(过程中网上搜索了一些相关文章,大部分说的是eclip ...

  7. HTML2

    1. IIS是一个软件,在"客户端服务器"模型中,它是服务器端软件,它主要提供基于HTTP的文档服务,主要是WWW     的发送,以及FTP的文件下载服务. VS提供了" ...

  8. 树莓派笔记之使用netselect选择最快Raspbian软件源

    背景: 之前在葉難大大的部落格里看到有讲可以使用netselect查找最快软件源,今天正好看到, 特此记下来,因为之前一直使用中国科学技术大学的源,结果发现不是我这里最快的. 注意: 以下仅对Rasp ...

  9. Python之路【第二十二篇】CMDB项目

    浅谈ITIL TIL即IT基础架构库(Information Technology Infrastructure Library, ITIL,信息技术基础架构库)由英国政府部门CCTA(Central ...

  10. IIS ARR 负载均衡

    阅读:http://www.cnblogs.com/jesse2013/p/dlws-loadbalancer2.html 自定义端口:http://www.th7.cn/Program/net/20 ...