linq用法大全.docx
- 文档编号:30220981
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:21
- 大小:195.35KB
linq用法大全.docx
《linq用法大全.docx》由会员分享,可在线阅读,更多相关《linq用法大全.docx(21页珍藏版)》请在冰豆网上搜索。
linq用法大全
查询内存对象
这一章中主要介绍了使用LINQ查询内存对象的一些基本语法。
在下一章将会有更高级的用法介绍。
本章中的示例数据是一个简单的出版社信息。
这是
数据文件。
下面的图表示了数据模型:
在进入本章以前,有必要了解LINQ能够查询哪些内存对象。
能够使用LINQ查询的内存对象
不是所有的内存对象都可以使用LINQ来查询。
正如前面说道的,能够使用LINQ查询的内存对象必须实现了IEnumerable
我们称实现了IEnumerable
因为在使用LINQ处理的时候就像是一个工厂按步骤处理原材料一样。
所幸的是所有的.NET泛型集合都实现了IEnumerable
也就是说我们可以对所有的.NET泛型对象集合使用LINQ查询。
下面是关于所有这些泛型集合的简单示例。
Arrays
我们可以对任何类型的数据使用LINQ查询。
包括多种类型的对象组成的集合。
如:
Object[]array={"string",12,true,'a'};
vartypes=array.Select(item=>item.GetType().Name)
.OrderBy(type=>type);
下面是执行结果:
Boolean
Char
Int32
String
此外,还可以为自定义的对象集合使用LINQ操作。
如下,就是对示例中的Book类使用LINQ操作。
Book[]books={
newBook{Title="LINQinAction"},
newBook{Title="LINQforFun"},
newBook{Title="ExtremeLINQ"}
};
vartitles=books
.Where(book=>book.Title.Contains("Action"))
.Select(book=>book.Title);
返回的结果为”LINQinAction”。
由此可见,对于普通的数据,我们可以很方便的使用LINQ来遍历其中的元素。
这对于我们在程序中处理数据是很方便的。
泛型List
在.NET中使用最为广泛的集合无疑是泛型的List。
泛型的List包括:
∙System.Collections.Generic.List
∙System.Collections.Generic.LinkedList
∙System.Collections.Generic.Queue
∙System.Collections.Generic.Stack
∙System.Collections.Generic.HashSet
∙System.Collections.ObjectModel.Collection
∙System.ComponentModel.BindingList
在这里,我们仅对List
其他的泛型List由于结构的不同在操作上可能有所不同。
List
newBook{Title="LINQinAction"},
newBook{Title="LINQforFun"},
newBook{Title="ExtremeLINQ"}
};
vartitles=books
.Where(book=>book.Title.Contains("Action"))
.Select(book=>book.Title);
输出的结果和上面的一样,是”LINQinAction”。
泛型字典
另外一个可以使用LINQ操作的常用集合是泛型字典(GenericalDictionary)。
.NET中的泛型字典包括:
∙System.Collections.Generic.Dictionary
∙System.Collections.Generic.SortedDictionary
∙System.Collections.Generic.SortedList
泛型字典实现了IEnumerable
KeyValuePair结构中包含了Key和Value的属性。
下面是一个简单的示例:
Dictionary
frenchNumbers.Add(0,"Zero");
frenchNumbers.Add(1,"un");
frenchNumbers.Add(2,"deux");
frenchNumbers.Add(3,"toris");
frenchNumbers.Add(4,"quatre");
varevenNumbers=fromiteminfrenchNumbers
whereitem.Key%2==0
selectitem.Value;
处理结果为:
Zero
deux
quatre
字符串
通常,字符串并不当成一个集合。
但实际上.NET的字符串实现了IEnumerable
因此,我们也可以对字符串使用LINQ。
如:
stringstrLine="Non-lettercharactersinthisstring:
8";
varNonLetterCount=strLine
.Where(c=>!
Char.IsLetter(c))
.Count();
处理结果为8。
即有8个非字母字符。
可能你也注意到了,在string的只能语法提示中没有IEnumerable
但是,我们还是可以使用它们。
除了上面提到的数据、泛型List、泛型字典和字符串以外,其他实现了IEnumerable
对于实现了非泛型的IEnumerable集合,如:
DataSet和ArrayList等,我们也可以使用LINQ查询,但是需要做一些特殊处理。
后面将会提到。
一些主要的标准查询操作符
下面将会介绍一些主要的标准操作符。
在书中包含了如何将查询结果绑定到ASP.NET和WinForm。
为了不分散注意力,我把这方面的内容虑过了。
有兴趣的话可以参考原书。
条件操作符where
Where操作符用来从数据源中过滤满足给定条件的数据。
下面是该扩展方法的定义:
publicstaticIEnumerable
thisIEnumerable
Func
例如,可以使用下面的查询列出价格在15以上的书:
varbooks=SampleData.Books.Where(book=>book.Price>=15);
使用查询表达式的写法如下,需要注意的是,使用查询表达式的时候必须带一个select语句。
varbooks=frombookinSampleData.Books
wherebook.Price>=15
selectbook;
Where还有一个重载版本,定义如下:
publicstaticIEnumerable
thisIEnumerable
Func
使用重载版本,我们可以根据index来指定记录。
如,下面的查询返回价格在15以上的前两条记录:
varbooks=SampleData.Books.Where(
(book,index)=>(book.Price>=15)&&
index>2);
使用查询表达式的时候不能使用重载版本(注:
个人认为不行。
需要确认。
)。
Select
Select用来选择要抽出的字段或者说属性。
可以像SQL一样取别名等。
下面是Select扩展方法的定义:
publicstaticIEnumerableSelect
thisIEnumerable
Func
下面的示例从Books中选择出所有Book的标题:
varbooks=SampleData.Books.Select(book=>book.Title);
对应的LINQ表达式写法为:
varbooks=frombookinSampleData.Books
selectbook.Title;
也可以在Select中使用匿名类型。
如:
varbooks=frombookinSampleData.Books
selectnew{Title=book.Title,
Publisher=book.Publisher.Name,
Author=book.Authors.First().LastName};
SelectMany
在说明SelectMany以前先来看一种情况。
从给定的示例数据中我们知道,一个Book对象可能有多个Author。
因此,Book的Authors属性背身就是一个集合。
如果我们需要列出所有Book的所有Author应该怎么做?
下面是一种可供选择的方法:
vartemp=SampleData.Books.Select(book=>book.Authors);
foreach(varauthorsintemp)
{
foreach(varauthorinauthors)
{
Console.WriteLine(author.FirstName+""+author.LastName);
}
}
很明显,这样的做法不能让人满意。
LINQ的SelectMany为我们提供了另一种选择。
下面是LINQ操作符的写法:
varauthors=SampleData.Books.SelectMany(book=>book.Authors);
这就大大的简化了代码。
实际上,SelectMany返回的也是一个IEnumberable
下面是SelectMany的定义:
publicstaticIEnumerableSelectMany
thisIEnumerable
Func
注意粗体部分,这也是与Select显著不同的地方。
表明它的返回仍然是一个IEnumerable的实例。
在LINQ表达式不提供对SelectMany的支持,但是可以使用多个From语句实现相同的功能:
varauthors=frombookinSampleData.Books
fromauthorinbook.Authors
selectauthor.FirstName+""+author.LastName;
相比较下,个人认为使用LINQ表达式更有灵活性。
例如,我们需要在列出所有的作者的同时列出书名。
使用LINQ操作符就不能实现。
但是,使用LINQ表达式就很容易了:
varauthors=frombookinSampleData.Books
fromauthorinbook.Authors
selectnew{Title=book.Title,
Author=author.FirstName+""+author.LastName};
另外需要说明一下,Select和SelectMany都支持在LINQ操作符中使用Index。
但是在LINQ表达式中还是不能使用。
下面是一个例子:
varbooks=SampleData.Books.Select((book,index)=>
new{index,Title=book.Title})
.OrderBy(book=>book.Title);
Distinct
与SQL一样,LINQ也使用Distinct来除去重复数据。
只是由于C#是强类型语言,在判断是不是重复的时候需要实现IEquatable
如果没有实现IEquatable
所以,我们可以自定义比较方式。
有兴趣的话可以查查看。
下面的示例是选出所有出过书的作者:
varauthors=SampleData.Books
.SelectMany(book=>book.Authors)
.Distinct()
.Select(author=>author.FirstName+""+author.LastName);
运行结果为:
JohnnyGood
GraziellaSimplegame
OctavioPrince
JeremyLegrand
JeremyPrince
注意:
对于比较,我有点迷惑。
一般的情况下我们都没有实现IEquatable
所以会使用Object.Equals()方法进行比较。
但是,我在自定义对象中重载了Equals函数后视乎仍然没有作用。
下面是我定义的Author类:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceLinqInAction.LinqBooks.Common
{
publicclassAuthor
{
publicStringFirstName{get;set;}
publicStringLastName{get;set;}
publicStringWebSite{get;set;}
publicoverrideboolEquals(objectobj)
{
AuthorobjAuthor=(Author)obj;
returnthis.FirstName==objAuthor.FirstName;
}
}
}
然后,再进行查询,结果仍然为:
JohnnyGood
GraziellaSimplegame
OctavioPrince
JeremyLegrand
JeremyPrince
在重载的Equals中,我将FirstName相同的Author判定为相同。
但运行结果明显不是我想要的。
这个问题有待于进一步研究。
这里做个标记。
转换操作符
使用转化操作符,LINQ可以将一个序列转化为其他的集合。
常用的转换操作符有:
ToList()、ToArray()和ToDictionary()。
在前面我们已经知道,使用转换操作符将会使查询立即执行,并拷贝一个镜像到另外一个集合。
这样,但查询的数据源发生改变的时候我们镜像(即,转换后的集合)就不会同步更新。
但是,有的时候我们需要使用转换操作。
一种通常的情况是当我们在using模块中使用查询的时候,由于退出using的时候已经关闭了数据连接。
使得查询就不再有效。
因此,常用的做法是在退出using模块以前拷贝一份镜像在另外一个集合中,这样我们就可以在using模块以外使用数据了。
这里就不再多说。
需要特别提一下的是ToDictionary()。
从名字可知,它将序列转化为一个Dictionary。
因此,我们需要提供一个参数作为KEY值。
如下面的代码表示要将序列转化为一个Dictionary,KEY值设为ISBN:
varbooks=SampleData.Books.ToDictionary(book=>book.Isbn);
需要注意的是,指定的KEY值是不能重复的。
因为Dictionary的KEY值就是唯一的。
如果指定了一个重复的KEY值将会导致运行时的错误。
如下面的示例,Books的Publisher就是重复的,就不能使用Publisher作为KEY值:
varbooks=SampleData.Books.ToDictionary(book=>book.Publisher);
聚集操作符
通常说的聚集操作符包括:
∙Count:
取得集合中的记录数。
∙Sum:
计算数字项目的和(注意是数字项目)。
∙Min和Max:
对集合中的数字项目找出最大值和最小值(注意是数字项目)。
下面是他们的使用方法的示例。
由于没有什么特别的,因此就不多做描述。
只是提醒注意他们的使用方法。
下面的使用方法都是合法的。
varbooks=SampleData.Books.ToDictionary(book=>book.Publisher);
varminPrice=SampleData.Books.Min(book=>book.Price);
varmaxPrice=SampleData.Books.Select(book=>book.Price).Max();
vartotalPrice=SampleData.Books.Sum(book=>book.Price);
varnbCheapBooks=SampleData.Books.Where(book=>book.Price<30).Count();
OrderBy,ThenBy,OrderByDescending,ThenByDescending
与SQL中一样,OrderBy用来对记录进行排序。
需要说明的是这里的排序、下面的嵌入查询和连接查询都是在内存中创建一个查询对象的新视图来仅此那个操作。
下面是OderBy的一个例子:
varresult=frombookinSampleData.Books
orderbybook.Publisher.Name,book.Pricedescending,book.Title
selectnew
{
Publisher=book.Publisher.Name,
Price=book.Price,
Title=book.Title
};
ObjectDumper.Write(result);
注意:
ObjectDumper是MS在示例代码中提供的方法。
上面的代码被编译为IL代码的时候如下:
ObjectDumper.Write(SampleData.Books.OrderBy
{
returnbook.Publisher.Name;
}).ThenByDescending
{
returnbook.Price;
}).ThenBy
{
returnbook.Title;
}).Select(delegate(Bookbook)
{
returnnew{Publisher=book.Publisher.Name,
Price=book.Price,
Title=book.Title};
}));
可以看出,当几个OrderBy连接在一起的时候,编译器在编译的时候实际上是按顺序调用对应的扩展方法。
另外,在这里你也可以看见LINQ查询是怎么样被延迟执行的。
嵌入查询
考虑这样的情况,假设需要查询每个出版社及其发行的书的名字。
应该怎么做?
下面的做法是一个可选的方式:
varresult=frombookinSampleData.Books
selectnew
{
Publisher=book.Publisher.Name,
Book=book.Title
};
上面的查询结果如下,可以看见,这并不能给我们一个有层次的、直观的感受:
Publisher=FunBooksBook=FunnyStories
Publisher=JoePublishingBook=LINQrules
Publisher=JoePublishingBook=C#onRails
Publisher=JoePublishingBook=Allyourbasearebelongtous
Publisher=FunBooksBook=BonjourmonAmour
使用嵌入查询,我们可以这样做:
varresult=frompublisherinSampleData.Publishers
selectnew
{
Publisher=publisher.Name,
Book=frombookinSampleData.Books
wherebook.Publisher.Name==publisher.Name
selectbook.Title
};
查询的结果大致如下,注意到IPublisher没有对应的Book。
FunBooks
FunnyStories
BonjourmonAmour
JoePublishing
LINQrules
C#onRails
Allyourbasearebelongtous
IPublisher
Grouping
我们可以使用Grouping实现和上面一样的效果。
代码如下:
varresult=frombookinSampleData.Books
groupbookbybook.PublisherintopubBooks
selectnew
{
Publisher=pubBooks.Key.Name,
Book=frompubBookinpubBooksselectpubBook.Title,
Count=pubBooks.Count()
};
执行结果大致如下:
FunBooks
FunnyStories
BonjourmonAmour
2
JoePublishing
LINQrules
C#onRails
Allyourbasearebelongtous
3
先看看group…by…into…是怎么工作的。
通过使用上面的表达式,所有的属于同一个Publisher的书都会被聚集到一个pubBooks中。
pubBoo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linq 用法 大全