LINQ之路 5:LINQ查询表达式
书写LINQ查询时又两种语法可供选择:方法语法(Fluent Syntax)和查询表达式(Query Expression)。
LINQ方法语法的本质是通过扩展方法和Lambda表达式来创建查询。C# 3.0对于LINQ表达式还引入了声明式的查询表达式,也叫查询语法,通常来讲,它是创建LINQ查询的更加快捷的方式。尽管通过查询语法写出的查询比较类似于SQL查询,但实际上查询表达式的产生并不是建立在SQL之上,而是建立在函数式编程语言如LISP和Haskell中的list comprehensions(列表解析)功能之上。本篇会对LINQ查询语法进行详细的介绍。
我们在前一篇LINAQ方法语法中所举的示例:获取所有包含字母”a”的姓名,按长度排序并将结果转为大写。下面是与之等价的查询表达式语法:
static void Main(string[] args)
{
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" }; IEnumerable<string> query =
from n in names
where n.Contains("a") // Filter elements
orderby n n.Length // Sort elements, (orderby n 改为 orderby n.Length, 感谢网友搏击的小船发现该处错误)
select n.ToUpper(); // Translate each element foreach (string name in query)
Console.WriteLine(name);
}
查询表达式总是以from子句开始,以select或者group子句结束。From子句定义了查询的范围变量(range variable),可以认为该变量是对输入sequence的一个遍历,就像foreach做的那样。下面这幅图描述了查询表达式的完整语法:
当然,.NET公共语言运行库(CLR)并不具有查询语法的概念。编译器会在程序编译时把查询表达式转换为方法语法,即对扩展方法的调用。这意味着,我们用查询表达式写出来的LINQ查询都有等价的方法语法。对于上例中的查询表达式,编译器会转换成下面的方法语法:
IEnumerable<string> query = names
.Where (n => n.Contains("a"))
.OrderBy(n => n.Length)
.Select (n => n.ToUpper());
然后,应用编译器对于方法语法的处理规则,上面的Where, OrderBy, Select查询运算符会绑定到Enumerable类中的相应扩展方法。
范围变量
范围变量是紧随from关键字之后定义的变量,一个范围变量指向当前操作符所对应的输入sequence中的当前元素。在我们的示例中,范围变量出现在每一个查询子句中,但要注意的是,变量实际是对不同sequence的遍历,因为Where、OrderBy、Select会有不同的输入sequence:
IEnumerable<string> query =
from n in names //n是我们定义的范围变量
where n.Contains("a") //n直接来自names array
orderby n.Length //n来自filter之后的subsequent
select n.ToUpper(); //n来自OrderBy之后的subsequent
当 编译器把上面的查询语法翻译成方法语法后,我们会更清楚的看到范围变量的这种行为:
IEnumerable<string> query2 = names
.Where(n => n.Contains("a")) //n直接来自names array
.OrderBy(n => n.Length) //n来自filter之后的subsequent
.Select(n => n.ToUpper()); //n来自OrderBy之后的subsequent
除了from关键字后面的范围变量,查询表达式还允许我们通过下面的子句引入新的范围变量:
- let
- into
- 额外的from子句
稍后我们会在“LINQ中的子查询、创建策略和数据转换”一篇中讨论他们的使用方法和适用场景。
查询表达式和方法语法
查询表达式和方法语法各有所长。对下面的场景来讲,用查询表达式写出来得查询会更加简洁:
- 使用let关键字引入新的范围变量
- 在SelectMany、Join或GroupJoin后引用外部范围变量时
在简单的使用Where、OrderyBy、Select时,两种语法结构并没有大的差别,此时可以根据你的喜好任意选择。
对于只有单个查询运算符组成的查询,方法语法会更加简短和易于理解。
最后,对于没有对应查询表达式关键字的查询运算符,我们就只能选择方法语法了。下面是存在对应查询表达式关键字的运算符:Where、Select、SelectMany、OrderBy、ThenBy、OrderByDescending、ThenByDescending、GroupBy、Join、GroupJoin。
组合查询语法
当一个查询运算符没有对应的查询语法时,我们可以组合使用查询语法和方法语法。唯一的约束是查询中的每一个查询语法部分必须是完整的,如以from开始以select或group结束。如下例:
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" }; // 计算包含字母”a”的姓名总数
int matches = (from n in names where n.Contains("a") select n).Count(); // 3
// 按字母顺序排序的第一个名字
string first = (from n in names orderby n select n).First(); // Dick
这种组合语法通常在书写更加复杂的查询时会具有优势,像上面这种简单的查询,我们只需要使用方法语法就能收到很好的效果:
int matches = names.Where(n => n.Contains("a")).Count(); //
string first = (names.OrderBy(n => n)).First(); // Dick
LINQ之路 5:LINQ查询表达式的更多相关文章
- 认识LINQ的第一步---从查询表达式开始
学习和使用C#已经有2个月了,在这两个月的学习中,深刻体会到,C#这门语言还真不适合编程初学者学习,因为它是吸取了很多其他语言,不仅是面向对象,还包括函数式语言的很多特性,导致它变成特性大爆炸的语言. ...
- linq to sql 动态构建查询表达式树
通过Expression类进行动态构造lamda表达式. 实现了以下几种类型,好了代码说话: public Expression<Func<T, bool>> GetAndLa ...
- 查询表达式和LINQ to Objects
查询表达式实际上是由编译器“预处理”为“普通”的C#代码,接着以完全普通的方式进行编译.这种巧妙的发式将查询集合到了语言中,而无须把语义改得乱七八糟 LINQ的介绍 LINQ中的基础概念 降低两种数据 ...
- LINQ之路 7:子查询、创建策略和数据转换
在前面的系列中,我们已经讨论了LINQ简单查询的大部分特性,了解了LINQ的支持计术和语法形式.至此,我们应该可以创建出大部分相对简单的LINQ查询.在本篇中,除了对前面的知识做个简单的总结,还会介绍 ...
- Linq查询表达式
目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. ...
- 《C#本质论》读书笔记(15)使用查询表达式的LINQ
15.1 查询表达式的概念 简单的查询表达式 private static void ShowContextualKeywords1() { IEnumerable<string> sel ...
- LINQ之路 8: 解释查询(Interpreted Queries)
LINQ提供了两个平行的架构:针对本地对象集合的本地查询(local queries),以及针对远程数据源的解释查询(Interpreted queries). 在讨论LINQ to SQL等具体技术 ...
- LINQ 查询表达式(C# 编程指南)
语言集成查询 (LINQ) 是一组技术的名称,这些技术建立在将查询功能直接集成到 C# 语言(以及 Visual Basic 和可能的任何其他 .NET 语言)的基础上. 借助于 LINQ,查询现在 ...
- Linq专题之创建Linq查询表达式
本节我们主要介绍一下如何创建查询集合类型,关系数据库类型,DataSet对象类型和XML类型的数据源的Linq查询表达式. 下面在实例代码ReadyCollectionData()函数创建了准备的数据 ...
随机推荐
- Power Network 分类: POJ 2015-07-29 13:55 3人阅读 评论(0) 收藏
Power Network Time Limit: 2000MS Memory Limit: 32768K Total Submissions: 24867 Accepted: 12958 Descr ...
- c#中的委托和事件(转)
引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...
- Uva 10562 看图写树
题目链接:https://uva.onlinejudge.org/external/105/10562.pdf 紫书P170 直接在二维数组上做DFS,用的fgets函数读入数据,比较gets函数安全 ...
- SharePoint自动化系列——Site/Web/List级别的导航菜单
转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 需求:在不同的测试用例中,对脚本中不确定的因素需要和用户交互来确定,比如选择哪个site,选择哪个 ...
- MSSQL删除字段时出现 服务器: 消息 5074,级别 16,状态 1,行 1 的解决办法
有的朋友在做用户维护字段的界面时,肯定发现一个问题,当用脚本:ALTER TABLE 表名 DROP COLUMN 字段名进行删除字段的操作时,会出现“服务器: 消息 5074,级别 16,状态 1, ...
- 模块shimgvw.dll已加载,但找不到入口点DllRegisterServer
[环境]Windows 7 / Windows Server 2008 [现象]在文件夹浏览器中不能显示图片缩略图. [错误信息]查系统日志,有如下消息:“模块shimgvw.dll已加载,但找不到入 ...
- 2016年11月2日 星期三 --出埃及记 Exodus 19:18
2016年11月2日 星期三 --出埃及记 Exodus 19:18 Mount Sinai was covered with smoke, because the LORD descended on ...
- HTTP请求&响应、POST与GET
HTTP请求&响应 既然说从入门级开始就说说Http请求包的结构.一次请求就是向目标服务器发送一串文本.什么样的文本?有下面结构的文本.HTTP请求包结构 请求包例子: POST /meme. ...
- Eclipse常用快捷键windows
Ctrl+1:快速修正Ctrl+W: 关闭当前文件ctrl+O:打开outlineCtrl+D: 删除当前行 Ctrl+L: 定位在某行Ctrl+Q:转到上次修改位置Ctrl+/:注释代码Ctrl+H ...
- Struts2的配置
Struts2的配置 Struts2可以通过Convention插件管理Action和结果映射,也可以通过使用XML文件进行管理,这两种方式各有好处:使用Convention插件管理减少了XML文件的 ...