书写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查询表达式的更多相关文章

  1. 认识LINQ的第一步---从查询表达式开始

    学习和使用C#已经有2个月了,在这两个月的学习中,深刻体会到,C#这门语言还真不适合编程初学者学习,因为它是吸取了很多其他语言,不仅是面向对象,还包括函数式语言的很多特性,导致它变成特性大爆炸的语言. ...

  2. linq to sql 动态构建查询表达式树

    通过Expression类进行动态构造lamda表达式. 实现了以下几种类型,好了代码说话: public Expression<Func<T, bool>> GetAndLa ...

  3. 查询表达式和LINQ to Objects

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

  4. LINQ之路 7:子查询、创建策略和数据转换

    在前面的系列中,我们已经讨论了LINQ简单查询的大部分特性,了解了LINQ的支持计术和语法形式.至此,我们应该可以创建出大部分相对简单的LINQ查询.在本篇中,除了对前面的知识做个简单的总结,还会介绍 ...

  5. Linq查询表达式

    目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. ...

  6. 《C#本质论》读书笔记(15)使用查询表达式的LINQ

    15.1 查询表达式的概念 简单的查询表达式 private static void ShowContextualKeywords1() { IEnumerable<string> sel ...

  7. LINQ之路 8: 解释查询(Interpreted Queries)

    LINQ提供了两个平行的架构:针对本地对象集合的本地查询(local queries),以及针对远程数据源的解释查询(Interpreted queries). 在讨论LINQ to SQL等具体技术 ...

  8. LINQ 查询表达式(C# 编程指南)

    语言集成查询 (LINQ) 是一组技术的名称,这些技术建立在将查询功能直接集成到 C# 语言(以及 Visual Basic 和可能的任何其他 .NET 语言)的基础上.  借助于 LINQ,查询现在 ...

  9. Linq专题之创建Linq查询表达式

    本节我们主要介绍一下如何创建查询集合类型,关系数据库类型,DataSet对象类型和XML类型的数据源的Linq查询表达式. 下面在实例代码ReadyCollectionData()函数创建了准备的数据 ...

随机推荐

  1. kmemleak的使用---内存泄露检测工具【转】

    转自:http://blog.csdn.net/lishenglong666/article/details/8287783 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] ...

  2. Android使用Application总结

    对于application的使用,一般是 在Android源码中对他的描述是; * Base class for those who need to maintain global applicati ...

  3. TreeView htc 改写

    call the function loadTree(treeviewId) when body is loaded <body onload="loadTree('tvSelect' ...

  4. setw和setfill控制输出间隔

    在C++中,setw(int n)用来控制输出间隔.例如:cout<<'s'<<setw(8)<<'a'<<endl;则在屏幕显示s a //s与a之间 ...

  5. keepalived + nginx双主 实战

    安装nginx nginx 下载地址 http://nginx.org/download/nginx-1.8.0.tar.gz 安装nginx的依赖关系 yum install pcre pcre-d ...

  6. 什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append性能好

    如果在编写代码的过程中大量使用+进行字符串评价还是会对性能造成比较大的影响,但是使用的个数在1000以下还是可以接受的,大于10000的话,执行时间将可能超过1s,会对性能产生较大影响.如果有大量需要 ...

  7. [xcode]Xcode查找函数(方法)调用及被调用

    参考资料:http://stackoverflow.com/questions/7145045/find-method-references-in-xcode 这个功能有的说是 Find Caller ...

  8. JavaScript DOM 编程艺术(第2版)读书笔记(2)

    JavaScript 语法 注释 单行注释:// 多行注释:/* */ "<!--"可以用作单行注释,由于和HTML的"<!--  -->"多 ...

  9. Design T-Shirt 分类: HDU 2015-06-26 11:58 7人阅读 评论(0) 收藏

    Design T-Shirt Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  10. 程序的链接和装入及Linux下动态链接的实现

    http://www.ibm.com/developerworks/cn/linux/l-dynlink/ 程序的链接和装入及Linux下动态链接的实现 程序的链接和装入存在着多种方法,而如今最为流行 ...