代码改变世界

走进Linq-Linq to Objects(上)基础篇

2008-07-22 14:50  横刀天笑  阅读(4584)  评论(11编辑  收藏  举报

本系列文章
走进Linq-Linq横空出世篇
走进Linq-辉煌的背后
走进Linq-Linq大观园

走进Linq-Linq to Objects(上)基础篇

 

话说自从编程大师走了后年轻的Coder很是郁闷了一会儿,他在想,为什么,我还以为是一个伟大的工程,我正准备把我写的代码作为一个opensouce project 分享出去,微软却干了。哎,还是要被微软牵着鼻子走一遭了。

 

在上一章里介绍了,Linq里那些查询操作都是给IEnumerable<T>接口添加的扩展方法(这些方法在Linq里被称为查询操作符),那么就可以以方法调用的方式使用Linq了:

 

books.Where(book=>book.Title.StartsWith(“L”)).OrderBy(book=>book.Price).Select(book=>new{key=book.Title,value=book.Price};

注意到没有,上面所有的方法都是操作IEnumerable<T>的,然后也是返回IEnumerable<T>类型的对象。可以把这些方法按照用途分个类(一些一看名字就知道意思的我就不做过多说明了)

用途

方法

映射的(就是将查询的结果映射成需要的结果)

Select(2个重载),SelectMany(4个重载)

条件过滤

Where(2个重载)OfType(这个方法是对IEnumerable扩展的,使用的时候要带上泛型参数,books.OfType<Book>(),意思就是从books集合里遍历元素,如果这个元素是Book类型或其子类型就将其添加到返回集合中)

排序(注意排序的方法放回的是继承自IEnumerable<T>IOrderedEnumerable<T>)

OrderBy(2个重载), OrderByDescending(2个重载), Reverse(不干别的,就是把IEnumerable<T>的顺序倒一下), ThenBy, ThenByDescending(这两个是对IOrderedEnumerable<T>的扩展方法,所以它只能用在OrderBy后面,它的作用就是在一个已排序的系列上再按照某个key排序一次)

分组

GroupBy(8个重载), ToLookup(4个重载,它们的作用是根据一个keyIEnumerable<T>转化为一个ILookUp<TKey,TValue>对象,这个对象将按照key分组元素)

联结

GroupJoin,Join

转型

Cast(Linq只能操作泛型的集合!谁告诉你Linq只能操作泛型的集合?这个方法就是干这事情的,它是对IEnumerable扩展的一个方法,将一个IEnumerable转型为IEnumerable<T>,然后你就可以享受Linq了,比如我用ArrayList保存一个User集合,ArrayList users = new ArrayList();但是Linq的那些什么Where啊,并没有对ArrayList所实现的接口IEnumerable进行扩展,怎么办?CastIEnumerable<T> myUsers = users.Cast<User>();就这么简单)

但是微软的哥们认为这种方式还是不人本化(或者那些哥们说,这样显得Linq太简单了,就添加几个扩展方法,显得咱们多没水平啊),如是他们弄出个“查询表达式”的玩意儿,像俺们这群搞C语系搞多了的人,突然一下子在C#里看到什么from啊,什么select啊,还真有点不习惯,那下面我们就来看看这个查询表达式到底是个啥玩意儿。

C# 3.0里又添加了一大把关键字,硬是造出个“查询表达式”(这又是一个语法糖)的东西来。实际上上面那段方法调用方式的Linq可以改写成这样:

from book in books
where book.Title.StartsWith(“L”)
orderby book.Price ascending
select 
new{key=book.Title,value=book.Price};

貌似很接近SQL,不过看上去总是感觉怪怪的,不过习惯就好,这种语法使用一种查询的风格去写代码,我想也许就是有了这个查询表达式,而不是方法调用的方式写代码,这东西称作语言集成查询才更贴近吧。在内部,C#编译器会将这段代码转换为方法调用。

这种风格初一看还真不好理解,Linq in Action这本书给出了一张图来说明查询表达式的语法:

 

(图中中括号说明是可选的,大括号说明是可以0个或多个)

一个查询表达式是从一个from子句开始的,后面跟着联结,条件过滤,排序,而且还可以是多个,最后以select或者group by结束。这里的from的作用就是引入一个变量,使用这个变量表示遍历跟在in后面的source序列里面的元素。

既然查询表达式最后都可以转换成方法的调用,那我们就来看看它们之间的映射关系吧,不过在C#里面有的方法调用没有对应的查询表达式vb.net里面却有。

GroupBy方法对应着group…by或者group…by…into…,有啥区别呢?group…by后面就不能跟东西了,这个查询表达式也就结束了,而group…by…into…还能继续,into后面跟着的是一个IGrouping<TKey,TResult>对象,已分组了,后面的表达式你就可以利用这个对象干些事情,比如求分组内的和啊等等。ThenBy方法就对应这orderby…,…(排序再排序)Join方法对应的查询表达式比较复杂:join…in…on…equals…join的作用和from一样,引入一个变量,用于表示跟在in后面序列内的对象,on后面跟着联结条件。

不过遗憾的是在C#里并不是所有的查询操作符(就是那些扩展方法)都有对应的查询表达式,所以有的时候你还是要借助方法调用的方式。

从查询表达式的写法上来看,如果比较简单的查询用查询表达式较好,但是复杂的查询,特别有join啊,还有多个from啊查询表达式将非常复杂,所以这个时候还是建议使用方法调用,这样可读性也许更好点。

 

Linq的理论部分也基本讲完了,本系列后续部分将借助实例讲解,我想可能好点,如果大家有什么更好的建议欢迎提出。

 

祝大家编程愉快

 

 

PS:貌似博客园发博客的编辑器贴代码不支持C# 3.0,一些关键字不高亮。