查询表达式提供了和SQL这样
![](/icons/70120de.gif)
关系化和分级
![](/icons/70120de.gif)
查询语言相类似
![](/icons/70120de.gif)
语言集成
![](/icons/70120de.gif)
语法
![](/icons/70120dou2.gif)
![](/icons/70120yi.gif)
个查询表达式是以from子句开头以select或者group子句结束
![](/icons/70120dou.gif)
这个
![](/icons/70120chushi.gif)
![](/icons/70120de.gif)
from子句可以在其后跟随任意多个from、let、where或者join子句
那么查询表达式中
![](/icons/70120de.gif)
这些子句都是做什么
![](/icons/70120de.gif)
呢?from子句是
![](/icons/70120yi.gif)
个引入了
![](/icons/70120yi.gif)
个覆盖整个序列
![](/icons/70120de.gif)
范围变量
![](/icons/70120de.gif)
生成器;let子句计算
![](/icons/70120yi.gif)
个值并传入
![](/icons/70120yi.gif)
个标识符来显示这个值;where子句是
![](/icons/70120yi.gif)
个从结果集中排除元素
![](/icons/70120de.gif)
过滤器;join子句用于比对源序列和另
![](/icons/70120yi.gif)
个序列中指定
![](/icons/70120de.gif)
键并找出匹配
![](/icons/70120de.gif)
对;select或group子句根据范围变量来指定结果
![](/icons/70120de.gif)
形式;
![](/icons/70120int.gif)
o子句可以将
![](/icons/70120yi.gif)
个查询
![](/icons/70120de.gif)
结果作为后续查询中
![](/icons/70120de.gif)
生成器并以此来拼接两个查询
前面提到了每
![](/icons/70120yi.gif)
条查询语句都必须是以from开头
![](/icons/70120de.gif)
![](/icons/70120dou.gif)
在from后面可以接除“;”、“,”和“=”以外所有
![](/icons/70120de.gif)
符号
![](/icons/70120dou.gif)
如果要在查询语句中使用这些标识符
![](/icons/70120dou.gif)
需要在前面加上“@”符号
C# 3.0并没有给查询表达式指定明确
![](/icons/70120de.gif)
执行语义
![](/icons/70120dou.gif)
准确地说
![](/icons/70120dou.gif)
C# 3.0把查询语句翻译为对依附于查询表达式模式
![](/icons/70120de.gif)
思路方法
![](/icons/70120de.gif)
![](/icons/70120diaoyong.gif)
![](/icons/70120dou.gif)
这些思路方法可以是对象例子思路方法也可以是扩展思路方法
![](/icons/70120dou.gif)
它们执行
![](/icons/70120de.gif)
才是实际
![](/icons/70120de.gif)
查询工作
![](/icons/70120dou2.gif)
查询表达式翻译为思路方法
![](/icons/70120diaoyong.gif)
![](/icons/70120de.gif)
过程是发生在类型绑定或者过载抉择的前
![](/icons/70120de.gif)
句法映射过程
![](/icons/70120dou.gif)
翻译可以保证语法正确但不能确保生成
![](/icons/70120de.gif)
![](/icons/70120yi.gif)
定是语法正确
![](/icons/70120de.gif)
C#代码
![](/icons/70120dou2.gif)
在翻译的后
![](/icons/70120dou.gif)
作为结果
![](/icons/70120de.gif)
思路方法
![](/icons/70120diaoyong.gif)
会被作为
![](/icons/70120yi.gif)
般
![](/icons/70120de.gif)
思路方法
![](/icons/70120diaoyong.gif)
![](/icons/70120dou.gif)
并且这可能会依次找出
![](/icons/70120cuowu.gif)
![](/icons/70120dou.gif)
例如思路方法不存在、参数中存在
![](/icons/70120cuowu.gif)
![](/icons/70120de.gif)
类型或者对范型思路方法
![](/icons/70120de.gif)
类型推断失败的类
![](/icons/70120de.gif)
![](/icons/70120yi.gif)
条查询语句
![](/icons/70120de.gif)
执行是以重复地应用后续翻译直到不再有更深
![](/icons/70120yi.gif)
层可进行
![](/icons/70120de.gif)
缩减
![](/icons/70120dou2.gif)
这些翻译根据优先权排列
![](/icons/70120dou.gif)
每个部分都假定前
![](/icons/70120yi.gif)
部分中
![](/icons/70120de.gif)
翻译已经被完全地执行
![](/icons/70120dou2.gif)
明确
![](/icons/70120de.gif)
翻译采用透明标志符(Transparent ident
![](/icons/70120if.gif)
iers)“*”来注入范围变量
接下来我们还是来看码说话吧
![](/icons/70120dou.gif)
这样可能更便于理解和掌握
![](/icons/70120dou2.gif)
前面提到
![](/icons/70120dou.gif)
查询表达式并不具备确切
![](/icons/70120de.gif)
执行语义
![](/icons/70120dou.gif)
而是用来被翻译成采用查询表达式模式
![](/icons/70120de.gif)
思路方法
![](/icons/70120diaoyong.gif)
![](/icons/70120dou.gif)
那我们就来看看这里所说
![](/icons/70120de.gif)
翻译到底是什么样子
![](/icons/70120de.gif)
吧
1: public
![](/icons/70120static.gif)
void Query
![](/icons/70120kh.gif)
2: { 3: Dictionary<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
> students =
![](/icons/70120new.gif)
Dictionary<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>
![](/icons/70120kh.gif)
; 4: students.Add("ZeroCool", 24); 5: students.Add("Michael", 21); 6: students.Add("Frieda", 22); 7: 8: IEnumerable<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>> queryResult = from student in students 9: where student.Value <= 23 10: orderby student.Value descending 11: select student; 12: 13: foreach (var student in queryResult) 14: { 15: Console.WriteLine(student.Key + " is " + student.Value + " years old."); 16: } 17: 18: Console.ReadLine
![](/icons/70120kh.gif)
; 19: }
上面这段代码要做
![](/icons/70120de.gif)
事情是从students这个集合里面找出所有年龄小于24岁
![](/icons/70120de.gif)
学生并按年龄降序排序
![](/icons/70120dou.gif)
我们着重来看
![](/icons/70120yi.gif)
下第8到第11行代码
![](/icons/70120dou2.gif)
我想所有写过SQL查询语句
![](/icons/70120de.gif)
朋友都会对这句话感到似曾相识
![](/icons/70120dou2.gif)
是
![](/icons/70120de.gif)
![](/icons/70120dou.gif)
它非常像SQL查询语句
![](/icons/70120dou.gif)
但又略有差别
![](/icons/70120dou.gif)
我们来看
![](/icons/70120yi.gif)
下这句话会被C# 3.0翻译成怎样
![](/icons/70120de.gif)
思路方法就会了解它是如何工作
![](/icons/70120de.gif)
了
1: IEnumerable<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>> queryResult 2: = students.Where(student => student.Value <= 23).OrderByDescending(student => student.Value).Select(student => student);
上面这行代码就是查询语句
![](/icons/70120de.gif)
翻译结果
![](/icons/70120dou.gif)
这行代码放在原先
![](/icons/70120chengxu.gif)
中替换掉第8到第11行代码依然是可以得出同样
![](/icons/70120de.gif)
结果
![](/icons/70120de.gif)
![](/icons/70120dou.gif)
或许这看上去还不太好理解吧
![](/icons/70120dou.gif)
那么我们用先前介绍过
![](/icons/70120de.gif)
表达式树来翻译
1: Func<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>, bool> filter = student => student.Value <= 23; 2: Func<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>,
![](/icons/70120int.gif)
> extract = student => student.Value; 3: Func<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>, KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>> result = student => student; 4: 5: IEnumerable<KeyValuePair<
![](/icons/70120string.gif)
,
![](/icons/70120int.gif)
>> queryResult = students.Where(filter).OrderByDescending(extract).Select(result);
这样
![](/icons/70120dou.gif)
虽然代码量多了
![](/icons/70120yi.gif)
点
![](/icons/70120dou.gif)
但
![](/icons/70120de.gif)
确理解起来方便了很多
![](/icons/70120dou2.gif)
翻译
![](/icons/70120de.gif)
结果是直接
![](/icons/70120diaoyong.gif)
原数据集合对象
![](/icons/70120de.gif)
Where思路方法选出符合条件
![](/icons/70120de.gif)
候选项
![](/icons/70120dou.gif)
然后在用OrderByDescending思路方法进行降序排序
![](/icons/70120dou.gif)
最后通过Select思路方法把这些结果返回回来
![](/icons/70120dou2.gif)
上面
![](/icons/70120de.gif)
例子虽然比较简单
![](/icons/70120dou.gif)
但是可以让我们很好地了解查询表达式
![](/icons/70120de.gif)
语法以及翻译
![](/icons/70120de.gif)
方式
![](/icons/70120dou.gif)
只要我们了解了最基本也是最核心
![](/icons/70120de.gif)
概念
![](/icons/70120dou.gif)
那么即使面对复杂
![](/icons/70120de.gif)
查询表达式也可以迎刃而解了
前面提到过
![](/icons/70120yi.gif)
个概念叫做“透明标识符”
![](/icons/70120dou.gif)
可能其定义比较抽象大家不太好理解
![](/icons/70120dou.gif)
现在我们借助
![](/icons/70120yi.gif)
个翻译过程来解释
![](/icons/70120yi.gif)
下到底什么事透明标识符吧
1: from customer in customers 2: from order in customer.Orders 3: orderby order.Total descending 4: select
![](/icons/70120new.gif)
{ customer.Name, order.Total };
我们假设有上面这句查询语句
![](/icons/70120dou.gif)
它
![](/icons/70120de.gif)
工作是从消费者
![](/icons/70120de.gif)
集合里找出每个消费者
![](/icons/70120de.gif)
名字和他
![](/icons/70120de.gif)
订购总量
![](/icons/70120dou.gif)
并按照每个消费者订购总量对他们进行降序排序
![](/icons/70120dou2.gif)
接下来我们来看看这句查询表达式将会被翻译成什么样子把
1: from * in 2: from customer in customers 3: from order in customer.Orders 4: select
![](/icons/70120new.gif)
{ customer, order } 5: orderby order.Total descending 6: select
![](/icons/70120new.gif)
{ customer.Name, order.Total }
现在透明标识符*已经出现了
![](/icons/70120dou.gif)
不过这还只是中间步骤
![](/icons/70120dou.gif)
我们继续往下翻译:
1: customers. 2: SelectMany(customer => customer.Orders.Select(order =>
![](/icons/70120new.gif)
{ customer, order })). 3: OrderByDescending(* => order.Total).Select(* =>
![](/icons/70120new.gif)
{ customer.Name, order.Total })
如果我们把透明标识符去掉
![](/icons/70120dou.gif)
那么上面几行代码就等效于:
1: customers. 2: SelectMany(customer => customer.Orders.Select(o =>
![](/icons/70120new.gif)
{ customer, order })). 3: OrderByDescending(x => x.order.Total).Select(x =>
![](/icons/70120new.gif)
{ x.customer.Name, x.order.Total })
其中
![](/icons/70120de.gif)
x是编译器生成
![](/icons/70120de.gif)
![](/icons/70120yi.gif)
个开发人员看不见摸不着
![](/icons/70120de.gif)
标识符
![](/icons/70120dou2.gif)
透明标识符不是
![](/icons/70120yi.gif)
个确切
![](/icons/70120de.gif)
语言特性
![](/icons/70120dou.gif)
它只作为查询表达式翻译过程中
![](/icons/70120de.gif)
![](/icons/70120yi.gif)
个中间步骤
当查询表达式注入
![](/icons/70120yi.gif)
个透明标识符时
![](/icons/70120dou.gif)
接下来
![](/icons/70120de.gif)
翻译步骤会将这个透明标识符传入到Lambda表达式和匿名对象
![](/icons/70120chushi.gif)
器中去
![](/icons/70120dou2.gif)
在这样
![](/icons/70120de.gif)
上下文中
![](/icons/70120dou.gif)
透明标识符具有以下
![](/icons/70120de.gif)
行为:
当
![](/icons/70120yi.gif)
个透明标识符作为Lambda表达式中
![](/icons/70120de.gif)
参数出现
![](/icons/70120de.gif)
时候
![](/icons/70120dou.gif)
相关联
![](/icons/70120de.gif)
匿名类型
![](/icons/70120de.gif)
成员将自动处于Lambda表达式体中
![](/icons/70120de.gif)
范围内;
当
![](/icons/70120yi.gif)
个含有透明标识符
![](/icons/70120de.gif)
成员处于当前范围内
![](/icons/70120dou.gif)
那么这个成员
![](/icons/70120de.gif)
成员也都处于当前范围内;
当
![](/icons/70120yi.gif)
个透明标识符作为
![](/icons/70120yi.gif)
个匿名对象
![](/icons/70120chushi.gif)
器中
![](/icons/70120de.gif)
成员声明符出现时
![](/icons/70120dou.gif)
它会引入
![](/icons/70120yi.gif)
个带有透明标识符
![](/icons/70120de.gif)
成员;
好了
![](/icons/70120dou.gif)
查询表达式就介绍到这里吧
![](/icons/70120dou.gif)
也许你觉得查询表达式有很多概念读起来比较抽象
![](/icons/70120dou.gif)
不那么便于理解
![](/icons/70120dou.gif)
但是我相信
![](/icons/70120dou.gif)
只要你动手多练习
![](/icons/70120yi.gif)
下
![](/icons/70120dou.gif)
很多概念都能很好地理解
![](/icons/70120de.gif)
![](/icons/70120dou2.gif)
![](/icons/70120smhl.gif)
C# 3.0 探索的旅
![](/icons/70120smhr.gif)
系列技术介绍文章也就到此为止了
![](/icons/70120dou.gif)
我相信C# 3.0为我们广大开发人员带来
![](/icons/70120de.gif)
这些新特性都能够是我们在很大程度上提高开发效率
![](/icons/70120dou.gif)
同时也增加了很多开发
![](/icons/70120de.gif)
乐趣
![](/icons/70120dou.gif)
随着微软不断有面向各个层面和领域
![](/icons/70120de.gif)
新技术问世
![](/icons/70120dou.gif)
我相信.NET平台也会逐渐成为
![](/icons/70120yi.gif)
个更加广泛、强大
![](/icons/70120de.gif)
技术平台
![](/icons/70120dou2.gif)
接下来
![](/icons/70120de.gif)
时间我会和大家
![](/icons/70120yi.gif)
起共同探讨
![](/icons/70120yi.gif)
下微软
![](/icons/70120de.gif)
另
![](/icons/70120yi.gif)
个重头戏——LINQ项目
![](/icons/70120dou.gif)
敬请关注!