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()函数创建了准备的数据 ...
随机推荐
- <mvc:annotation-driven />与<context:annotation-config />
Spring家族的配置中这两个配置的意义,说具体点其实根据标签的shecma就能看出来,mvc,主要就是为了Spring MVC来用的,提供Controller请求转发,json自动转换等功能,而co ...
- Javascript Window Location
window.location 对象在编写时可不使用 window 这个前缀. URL : 统一资源定位符 (Uniform Resource Locator) 说明: 完整的URL示例:scheme ...
- inupt textarea提示文字(点击消失,不输入恢复)
<input name="textfield" type="text" maxlength="20" value="请输入 ...
- cut DEMO
分割后得到列: cat /etc/passwd|head -n 5 | cut -d : -f 1,6
- eclipse怎么设置字体大小
eclipse怎么设置字体大小
- PHP array_count_values() 函数用于统计数组中所有值出现的次数。
定义和用法 array_count_values() 函数用于统计数组中所有值出现的次数. 本函数返回一个数组,其元素的键名是原数组的值,键值是该值在原数组中出现的次数. 语法 array_count ...
- HDU 4453:Looploop(Splay各种操作)
http://acm.hdu.edu.cn/showproblem.php?pid=4453 题意:很多种操作:1.add x,将从光标起的 k2 个数全部加上 x:2.reverse,将从光标起的 ...
- symfony中twig的模板载入
模板 载入模板 {% include ‘sidebar.html’ %} 当前模板的变量也会传递到 被include的模板里,在那里面可以直接访问你这个模板的变量. {% for comment in ...
- linux命令介绍:df使用介绍
linux中df命令参数功能:检查文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 语法:df [选项] 说明:linux中df命令可显示所有文件系统对 ...
- StringBuffer类的方法
public class Page116 { /** * StringBuffer类的练习 * @param args * @throws IOException */ public static v ...