c3.0與net3.5高級(jí)編程-第4章linq查詢基礎(chǔ)_第1頁(yè)
c3.0與net3.5高級(jí)編程-第4章linq查詢基礎(chǔ)_第2頁(yè)
c3.0與net3.5高級(jí)編程-第4章linq查詢基礎(chǔ)_第3頁(yè)
c3.0與net3.5高級(jí)編程-第4章linq查詢基礎(chǔ)_第4頁(yè)
c3.0與net3.5高級(jí)編程-第4章linq查詢基礎(chǔ)_第5頁(yè)
已閱讀5頁(yè),還剩31頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

4LINQ關(guān)系日漸復(fù)雜。從而帶動(dòng)了技術(shù)的不斷發(fā)展,越來(lái)越多的數(shù)據(jù)格式被應(yīng)用到各種的數(shù)據(jù)源學(xué)習(xí)不同的數(shù)據(jù)查詢語(yǔ)言,比如,查詢SQL數(shù)據(jù)庫(kù)的T-SQL、查XML數(shù)據(jù)的DOM結(jié)構(gòu)等。為了解決上面的問(wèn)題,微軟在.NET3.5版中推出一項(xiàng)具有突破性的新特性——語(yǔ)言集成查詢(LINQ)。LINQLanguageIntegrateQuery的縮寫,它在對(duì)象和數(shù)據(jù)之間建立一種對(duì)應(yīng)關(guān)系,可以使用內(nèi)存對(duì)象的方式查詢數(shù)據(jù)集合。LINQ使查詢成為C#中的一種C#SQL語(yǔ)句的查詢表達(dá)式,從而實(shí)現(xiàn)數(shù)據(jù)LINQ不是簡(jiǎn)單地在C#中嵌套查詢表達(dá)式,而是將查詢表達(dá)式作為C#的一種語(yǔ)法。查詢表達(dá)式的數(shù)據(jù)源是包含一組數(shù)據(jù)的集合對(duì)象(IEnumerable<T>或IQueryable<T>類VisualStudio2008編寫代碼使用只能感知功能,使得編碼更快捷和輕松。LINQ還可以通過(guò)函數(shù)的形式提供過(guò)濾從而,為不同類型數(shù)據(jù)源的數(shù)據(jù)查詢提供一種統(tǒng)一的編碼方式。在.NET類庫(kù)中,LINQ相Enuerabe<>接口:它表示可以查詢的數(shù)據(jù)集合,一個(gè)查詢通常是逐個(gè)對(duì)集合Enueabe>EnumerableIEnumerbale<T>LINQ標(biāo)準(zhǔn)查詢運(yùn)LINQtoObjectIEnumerable<T>IQueryable<T>的內(nèi)存數(shù)據(jù)集合,這也是LINQ的基礎(chǔ),本章將詳細(xì)介紹這方面的內(nèi)容。LINQtoADO.NETADO.NET數(shù)據(jù)集,這里將數(shù)據(jù)庫(kù)中的表結(jié)構(gòu)映射到類結(jié)構(gòu),并通過(guò)ADO.NETLINQ進(jìn)行數(shù)據(jù)查詢。本書第8章將詳細(xì)介紹這一技術(shù)。LINQ9章將詳細(xì)介紹這一3種常見的數(shù)據(jù)類型之外,.NET3.5LINQ提供了支持,用戶可以根據(jù)需要實(shí)現(xiàn)第的LINQ支持程序,然后通過(guò)LINQ獲取自定義的數(shù)據(jù)源。如何使LINQ作為一種數(shù)據(jù)查詢編碼方式,它本身并不是獨(dú)立的開發(fā)語(yǔ)言,也不能進(jìn)行應(yīng)用程序開發(fā)。但是在.NET3.5中,可以在C#中集成LINQ查詢代碼。在任何源代碼文件中,要使用LINQ查詢功能,必須System.Linq命名空間。使用LINQtoXML要System.Xml.Linq命名空間,使用LINQtoADO.NET要System.Data.Linq命名空間。代碼如下所示。usingSystem.Linq;usingSystem.Xml.Linq;usingSystem.Linq;usingSystem.Xml.Linq;注意:在VisualStudio2008中,通過(guò)向?qū)?chuàng)建項(xiàng)目時(shí),會(huì)自動(dòng)System.Linq命名空4-1所示。其中,query1LINQ查詢,foreach語(yǔ)句則是遍歷查L(zhǎng)INQ查詢,它并沒有staticvoidMain(string[]{

示例代碼4-int[]ary={1,2,5,4,3,9,8,7varquery1fromvalinaryselectval;foreach(varitemin{}}

//定義數(shù)//打印輸注意:LINQ是在.NET3.5版之后新增的,所以在.NET2.0及早期版本程序中直接使用VisualStudio2008將程序自動(dòng)轉(zhuǎn)化到.NET3.5版本。LINQ查L(zhǎng)INQ最具突破性的優(yōu)勢(shì)在于將文本查詢與對(duì)象操作完美集成,它讓查詢數(shù)據(jù)和操作對(duì)象一樣安全和輕松。查詢(Query)是LINQ的概念之一。例如,下面代碼中的selectfrom是關(guān)鍵字,分別用來(lái)指定要查詢的結(jié)果和數(shù)據(jù)源。fromstudentsLINQ中的查詢和傳統(tǒng)的查詢有一些相似之處,它同樣可以采用具有一定語(yǔ)義的文本4-1query1LINQ中稱為查詢表達(dá)式。另外,LIIQIEnumerable<T>IQueryable<T>的對(duì)象,所以可以通過(guò)一種使用對(duì)象的方式(使用屬性、調(diào)用方法等)使用它,這種方式在LINQ中LINQ查詢的目的是從指定的數(shù)據(jù)源中查詢滿足符合特定條件的數(shù)據(jù)元素,并且通過(guò)根據(jù)需要對(duì)這些查詢的元素進(jìn)行排序、連接等操作。所以LINQ查詢包括如下幾個(gè)主要每個(gè)數(shù)據(jù)集包含一系列的元素。數(shù)據(jù)集是一個(gè)類型為IEnumerable<T>或息集合中,查詢A只是查詢學(xué)生的,查詢B要查詢學(xué)生的和各科成績(jī),C則需要學(xué)生各科成績(jī)的總分(需要另外計(jì)算),而不是原始數(shù)據(jù)中的各科成績(jī)。目標(biāo)數(shù)據(jù)用來(lái)指定查詢的具體想要的是什么數(shù)據(jù)。在LINQ中,它定義了4-1query1就只包含了數(shù)據(jù)源和目標(biāo)數(shù)據(jù)兩個(gè)必備元素。本章后面的章節(jié)將進(jìn)一步介紹LINQ查詢的具體使用方法。LINQ查詢表達(dá)式是查詢語(yǔ)言最基本的編寫格式。同樣,LINQ查詢表達(dá)式是一種直觀、簡(jiǎn)LINQ查詢表達(dá)式的格式和具體應(yīng)用,查詢表達(dá)LINQLINQ查詢LINQ查詢的方法。查詢表達(dá)式由查詢關(guān)鍵字和對(duì)應(yīng)的操作數(shù)關(guān)鍵字,從而更好地與LINQ集成。C3.04.1所示。通過(guò)使用這些查詢關(guān)鍵4.1查詢表達(dá)式關(guān)鍵 4.3節(jié)詳細(xì)介紹查from子句指定數(shù)據(jù)在4.1.3節(jié)講到,數(shù)據(jù)源是LINQ查詢中必不可少的元素。數(shù)據(jù)源是實(shí)現(xiàn)泛型接口IEnumerable<T>或IQueryable<T>IEnumerable<T>簡(jiǎn)單理解成一個(gè)包含合。在.NETIEnumerable<T>,所以可以直接將這些數(shù)據(jù)對(duì)象作為數(shù)據(jù)源在LINQ查詢中使用。from子句的編寫格式如下所示。其中,dataSource表示數(shù)據(jù)源,localVar表示單fromlocalVarin 一般情況下,不用為from子句localVar元素指定數(shù)據(jù)類型,編譯器會(huì)根據(jù)數(shù)據(jù)源類型為它分配合適的類型,通常元素類型為IEnumerable<T>中的類型T。例如,當(dāng)數(shù)據(jù)源為IEnumerable<int>localVarintIEnumerable<string>時(shí),編譯器為localVar指定類型string。如示例代碼4-2所示aryint[]類型,默認(rèn)實(shí)現(xiàn)了接口IEnumerable<int>,所以val1的類型為[]ary={1,2,3,5,7varquery1fromval1inaryselectval1;

示例代碼4-//定義int數(shù)組ary為數(shù)據(jù)4-2中,希望ary中的object類型進(jìn)行處理,而不是作int。這就from子句中為localVar指定目標(biāo)類型,如示例4-3所示val2object類型。由ary中的元素int類型。屬于object類型的子類型,所以可以直接轉(zhuǎn)換為object類型。示例代碼4-int[]int[]ary={1,2,3,5,7//定義int數(shù)組aryvarquery2 //LINQ查詢數(shù)據(jù)源ary中所有元素,元素類型指定為fromobjectval2inaryselectval2;值得一提的是,編譯器并不會(huì)檢查本地變量(localVar元素)的具體類型。所以當(dāng)指定類型不正確時(shí),編譯時(shí)并不會(huì)報(bào)錯(cuò)。如示例代碼4-4所示,本地參數(shù)val3指定為Studentval3intval3Student類型是錯(cuò)誤,編譯器并不會(huì)foreach語(yǔ)句中使用該查詢時(shí),會(huì)在運(yùn)行時(shí)進(jìn)行類型檢查,從而產(chǎn)生示例代碼4-intintary1,2,35,7};//intaryvarquery3= fromStudentval3inaryselectforeachvaritemin { }Debug示例4-4時(shí),產(chǎn)生的異常提示如圖4.1所示,即不能將一int類型的變量強(qiáng)制轉(zhuǎn)換成Student類型。圖4.1類型錯(cuò)誤建議:如果沒有特別需要,作者建議使用不指定類型的本地變量,讓編譯器自動(dòng)根據(jù)數(shù)select子句指定目標(biāo)select selectStudent類,該類表ToString()Student類的字符串形式。Student類的具體實(shí)現(xiàn)如示例代碼4-5所示。示例代碼4-classLessonScore{publicLessonScore(stringlesfloatscr{this.Lesson=les;this._Score=scr;}privatefloat_Score表示課程成績(jī)的字段和屬性publicfloatScore{get{return }publicstring_Lesson表示課程名稱的字段和屬性publicstringLesson{get{returnthis._Lesson;}publicoverridestringToString(//重 ToString()方法,按照特定格式打印成績(jī)信{stringstrstring.Format("{0}---{1}分this._Lessonthis._Score);returnstr;}} class{privatestring_Name;//表示學(xué) publicstringget{returnthis._Name;}privatestring_XingBie;//表示學(xué) publicstringXingBieget{returnthis._XingBie;} privateuint_Age;publicuintAge{get{returnthis._Age;}privateList<LessonScore>//表示學(xué)生成績(jī)單的字段和屬性,一個(gè)LessonScorepublicList<LessonScore>{get{returnthis._Scores;}//構(gòu)造函數(shù),傳 publicStudent(stringname,stringxb,uintage,List<LessonScore>{this._Age=age;this._Name=name;this._XingBie=xb;this._Scores=scrs;}publicStudent(stringname,stringxb,uint//構(gòu)造函數(shù)、傳 {this._Age //設(shè)this._Name //設(shè)this._XingBie //設(shè)this._Scores //設(shè)置成績(jī)單,默認(rèn)為}{stringstr=string.Format("{0}-{1}-{2}", this._Name,this._Age,this._XingBie);return}}select子句中如果不指定元素的具體類型,編譯器會(huì)將查詢中元素的類型自動(dòng)設(shè)置為select4-6fromval1stAry元素么自動(dòng)判斷為Student類型,query1的類型則為IEnumerable<Student>。示例代碼4-StudentStudentstAry //創(chuàng)建學(xué)生列表stAry{new 男new 權(quán)宜男new 紅女new 碼男new 女varquery1 fromval1instAryselectval1;foreach(Studentitemin //query1{ }調(diào)用Student類的ToString()方法來(lái)獲得文本格式。-20--20-select子句中要選擇的目標(biāo)數(shù)據(jù)不僅可以為數(shù)據(jù)源中的元素,還可以是該元素的不同屬性)作為查詢結(jié)果,其是IEnumerable<string>類型,query3則是將學(xué)生的(Name屬性)的字符數(shù)作為查詢結(jié)果,其是IEnumerable<int>類型。示例代碼4-varvarquery2 //query2stAryfromval2instAryselectval2.Name;foreachstringitemin {System.Console.Write("{0},",} ine(varvarquery3//查詢query3返回?cái)?shù)據(jù)源stAry中所有學(xué)生 fromval3instAryforeachintitemin {System.Console.Write("{0},",}第2行是query3的查詢結(jié)果,即所有學(xué)生字符數(shù)集合。 ,LINQselect子句中使用匿名類型來(lái)解決這類問(wèn)題。如示例代碼4-8中,查詢query4的select子句通過(guò)類型定義返回結(jié)果。因?yàn)樵诰幋a中無(wú)法表示類型,所以在foreach中只能通過(guò)var(可變類型)示例代碼4-////查詢query4返回?cái)?shù)據(jù)源stAry中學(xué)生 長(zhǎng) varquery4fromval4inselectnewval4.Nameval4.AgeNameLenval4.Name.Lengthforeach(variteminquery4) //打印查詢query4的元素{ }{{==,Age=20,NameLen=2權(quán)宜Age22NameLen}{=紅Age23NameLen3{=碼Age21NameLen3{=,Age=18,NameLen=2技巧:select子句中的元素指定具體數(shù)據(jù)類型。另外,如果查詢where子句指定篩選條LINQ查詢不會(huì)如前面的示例代碼這么簡(jiǎn)單,經(jīng)常還需要對(duì)數(shù)據(jù)源中的元素LINQwhere子句指定查詢的過(guò)濾條件,它的格式如下。其中,expression是一個(gè)邏輯表達(dá)式,返回布爾值where where子句中的條件表達(dá)式,可以用&&和||指定多個(gè)條件的邏輯運(yùn)算關(guān)系。其中,&&表示邏輯并,||表示邏輯或。它們的計(jì)算關(guān)系如表4.2所示。4.2where子句中的邏輯操exp1&&exp1||真真真真真假假真假真假真假假假假4-9query1whereary中所15的元素。查詢query2where子句的條件中使用&&運(yùn)算,查詢數(shù)組ary中大于1040query3where子句的條件中使用||ary中小于示例代碼4-staticstaticvoidUseSimpleWhere({int[]ary{1,3,9,54,20,10,23,12,18,60,37varquery1fromval1inarywhereval1>15selectval1;foreach(varitemin{//打印query1} ine(varquery2 //查詢query2ary中所有大于10且小于fromval2inwhere(val2>10)&&(val2<40)selectval2;foreachvaritemin {} ine(varquery3 //查詢query3ary中所有小于10或大于fromval3inwhere(val3<10)||(val3>40)selectval3;foreachvaritemin {} ine(}54,54,20,23,18,60,20,23,12,18,1,3,9,54,LINQwhere子句來(lái)進(jìn)行多個(gè)條件過(guò)where子句的條件才能作為查詢結(jié)果。這樣,可以將示例代碼4-9中的查詢query2等價(jià)寫成示例代碼4-10中的查詢query4query4中的元素只有同時(shí)滿足兩個(gè)where子句中的條件,才會(huì)作為查詢結(jié)果。示例代碼4-varquery4fromval4inarywhereval4>10whereval4<40selectval4;當(dāng)出現(xiàn)多個(gè)邏輯并(&&運(yùn)算)where子句orderby子句進(jìn)行排LINQorderby子句對(duì)查詢結(jié)果進(jìn)行排序操作。orderby子句用來(lái)對(duì)查詢結(jié)果進(jìn)行升序或降序排序。它的格式如下:orderbyelement 其中,element是要進(jìn)行排序的字段,它可以是數(shù)據(jù)源中的元素,也可以是對(duì)元素的操ascending4-11query1ary中query2ary中的所有元素,并按照降序示例代碼4-staticstaticvoidUseSimpleSort({int[]ary{9,54,20,11,3,0,23,12,18,60,37varquery1fromval1inaryorderbyval1selectval1;foreach(varitemin{//query1ary} ine(varquery2 //query2aryfromval2inorderbyorderbyval2descendingselectval2;foreach(varitemin{}}示例代碼4-11的輸出如下所示。query1asending。query2的查詢結(jié)果則按照降序排序,指定為desending0,0,3,9,11,12,18,20,23,37,54,60,54,37,23,20,18,12,11,9,3,示例代碼4-staticstatic{plexSort(StudentstAry //創(chuàng)建學(xué)生信息數(shù)組stAry{new 男new 權(quán)宜男new 紅女new 碼男new 女//查詢query3返回stAry中所有元素,主要 varquery3fromstinorderbyst.Name.Lengthascending,st.Agedescendingselectst;foreachvaritemin { }}時(shí),只有最后一個(gè)orderby子句有效,前面的orderby子句都無(wú)效。group子句進(jìn)行分LINQgroup子句實(shí)現(xiàn)對(duì)查詢結(jié)果的分組操作。在LINQ中,group子句的常用格式如下:groupelementby 其中,element表示作為查詢結(jié)果返回的元素,key表示分組條件。group子句返回類型為IGrou<TKey,ement>的查詢結(jié)果。其中,TKey的類型為參數(shù)key的數(shù)據(jù)類型,ementelement注意:IGrou<TKey,ement>可以看成一個(gè)HashTable內(nèi)部嵌套一個(gè)List列表的數(shù)內(nèi)層foreach按照對(duì)應(yīng)的元素列表遍歷。在示例代碼4-13中,首先定義一些學(xué)生信息stAry作為數(shù)據(jù)源,然后查詢query1中通過(guò)group子句表示按照學(xué)生(st.XingBie)對(duì)查詢結(jié)果學(xué)生(st)進(jìn)行分組。最后,通過(guò)嵌foreach遍歷查詢結(jié)果中的元素1foreach按關(guān)鍵2foreach示例代碼4-staticstaticvoidUseSimpleGroupBy({StudentstAry //創(chuàng)建學(xué)生信息數(shù)組stAry{new 男new 權(quán)宜男new 紅女new 碼男new 女varquery1fromstin//查詢query1返回stArygroupstbyforeachvargrpin //打印query1{ { ine("\t{0}",}}}男男-20-權(quán)宜-22-碼碼-22-女selectgroup子句對(duì)其進(jìn)行重新查groupgroupelementbykeyinto子句使用。如示例代碼4-14中所示,首先用group子句將學(xué)生信息按照分組,并且用into關(guān)鍵字將分組結(jié)果保存到變量stGrp中。然后通過(guò)orderby子句按照(stGrp.Key)進(jìn)行排序,用select子句進(jìn)行再次查詢。示例代碼4-staticstatic{plexGroupBy(StudentstAry //創(chuàng)建學(xué)生信息數(shù)組stAry{new 男new 權(quán)宜男new 紅女new 碼男new 女//查詢query2返回stAryvarquery2fromstingroupstbyst.AgeintostGrporderbystGrp.KeydescendingselectstGrp;foreachvarstGrpin //打印query2{ ine("{0}歲的學(xué)生 foreachvarstin //打印query2{ ine("\t{0}",}}}2222歲的學(xué)生20歲的學(xué)生18歲的學(xué)生-18-類型,stGrp是group子句查詢結(jié)果是IGrou<int,Student>,最后query2通過(guò)selectIEnumerable<T>stGrpquery2的最終類型為IEnumerable<IGrou<int,Student>>。from子句進(jìn)行復(fù)合查面的示例代碼中,都只是使用一個(gè)數(shù)據(jù)源(即只使用一個(gè)from子句)。但實(shí)際開LINQfrom復(fù)合查詢,第一種是對(duì)同一個(gè)數(shù)據(jù)源中的元素進(jìn)行嵌套查詢。據(jù)源進(jìn)行查詢,內(nèi)層from子句則對(duì)元素中的數(shù)據(jù)源進(jìn)行查詢。stfrom子句對(duì)元素的成績(jī)列表(st.Scores)進(jìn)行查詢,而where子句則表示只選擇學(xué)生的成績(jī)高于80分的成績(jī)。示例代碼4-staticstaticvoidUseUnionFrom({Student[]stAry{//創(chuàng)建學(xué)生信息數(shù)組stArynew 男newList<LessonScore>{newLessonScore("英語(yǔ)",80.5f),newLessonScore("數(shù)學(xué)70.0f)newLessonScore("語(yǔ)文",new 權(quán)宜男newList<LessonScore>{newLessonScore("英語(yǔ)",90.5f),newLessonScore("數(shù)學(xué)80.0f)newLessonScore("語(yǔ)文",new 紅女newList<LessonScore>{newLessonScore("英語(yǔ)",80.5f),newLessonScore("數(shù)學(xué)50.5fnewLessonScore("語(yǔ)文",new 碼男newList<LessonScore>{newLessonScore("英語(yǔ)",50.5f),newLessonScore("數(shù)學(xué)80.0f)newLessonScore("語(yǔ)文new 女newList<LessonScore>{newLessonScore("英語(yǔ)",80.5f),newLessonScore("數(shù)學(xué)90.0f)newLessonScore("語(yǔ)文",//query1from//第二個(gè)from子句的元素從第一個(gè)fromvarquery1fromstinstAryfromscrinst.Scoreswherescr.Score>80groupnew{st.Name,scr}byforeachforeach(vargrpin{//打印查詢query1 foreachvaritemin //打印查詢query1{ ine("\t{0}",}}}4-15 分的成績(jī)才能成為查詢結(jié)果。其中,成績(jī)信息通過(guò)LessonScore.ToString()產(chǎn)生{{Namescr英語(yǔ)---80.5{Name權(quán)宜scr英語(yǔ)---90.5紅{Name紅scr英語(yǔ)---80.5{Name{Namescr英語(yǔ)---80.5scr數(shù)學(xué)---90分fomromfrom子句中元素的屬性和方法等。從理論上說(shuō),它可以是任何的可以作為數(shù)據(jù)源的對(duì)象。fromfrom子句都從一個(gè)數(shù)據(jù)源提取數(shù)據(jù),通常還where子句對(duì)數(shù)據(jù)進(jìn)行過(guò)濾。如示例代碼4-16所示,查詢query1的第1個(gè)from子句從intAry1中獲取數(shù)據(jù)并保存到val1中。第2個(gè)from子句從intAry2val2中。where子句表示只提取能整除val1val2值。示例代碼4-staticstaticvoidUseUnionFrom2({int[]intAry1={5,15,25,30,33,//intAry1intAry2int[]intAry2={10,20,30,40,50,60,70,80,90,varquery1 //查詢query1從兩個(gè)數(shù)據(jù)源intAry1和fromval1inintAry1fromval2inintAry2whereval2%val1==0groupval2byval1;{System.Console.Write("{0}:",grp.Key);foreach(varvalingrp){} ine(}}intAry133intAry2中沒有任何數(shù)字可以被它整除,所以它并沒有出現(xiàn)5:5:10203040506070809015:306025:5030:306050:50注意:理論上,多from子句的復(fù)合查詢可以包括任何from子句。但是過(guò)多的使用超過(guò)3個(gè)以上的from子句。join子句進(jìn)行聯(lián)LINQjoin子句實(shí)現(xiàn)聯(lián)接操作。join子句可以將來(lái)自不同源序列,并且在對(duì)象模型中沒有直接關(guān)系的元素相關(guān)聯(lián),唯join子句進(jìn)行內(nèi)部聯(lián)join子句的格式如下所示。其中,dataSource表示數(shù)據(jù)源,它是聯(lián)接要使用的第二個(gè)數(shù)據(jù)集。element表示dataSource中元素的本地變量。exp1和exp2表示joinelementindataSourceonexp1equals 4-17query1intAry1intAry2聯(lián)接。其中,fromintAry1,joinintAry2,on…equals表示在val1val2上進(jìn)行聯(lián)接。當(dāng)val1%5val2%15有相同的值時(shí),select子句將val1和val2選擇為查詢結(jié)果。示例代碼4-staticstaticvoidUseInnerJoin({int[]intAry1={5,15,25,30,33,//創(chuàng)建整數(shù)數(shù)組intAry1int[]intAry2={10,20,30,50,60,70,//創(chuàng)建整數(shù)數(shù)組intAry2////query1joinvarquery1=fromval1injoinval2inintAry2onval1%5equalsval2%15selectnew{VAL1=val1,VAL2=val2};foreachvaritemin { }}4-17val1%5val2%15相{{VAL1=5,VAL2=30{VAL1=5,VAL2=60{VAL1=15,VAL2=30{VAL1=15,VAL2=60{VAL1=25,VAL2=30{VAL1=25,VAL2=60{VAL1=30,VAL2=30{VAL1=30,VAL2=60{VAL1=40,VAL2=30{VAL1=40,VAL2=60用join子句進(jìn)行分組聯(lián)join子句的另外一種用法——分組聯(lián)接。分組聯(lián)接的格式如下所示。其中,into關(guān)鍵字表示將這些數(shù)據(jù)分組并保存到grpName中,grpName是保存一組數(shù)據(jù)的集合。joinelementindataSourceonexp1equalsexp2into 4-184-17完全一樣。但是它在示例代碼4-staticstaticvoidUseGroupJoin({int[]intAry1={5,15,25,30,33,40//創(chuàng)建整數(shù)數(shù)組intAry1int[]intAry2={10,20,30,50,60,70,80//創(chuàng)建整數(shù)數(shù)組intAry2//query1joinvarquery1=fromval1injoinval2inintAry2onval1%5equalsval2%15intoselectselectnew{VAL1=val1,VAL2GRP=foreach(varobjin{foreach(varvalinobj.VAL2GRP){} ine(}}4-18intAry1中的存在匹配元素也會(huì)產(chǎn)生一個(gè)空的列表,如intAry1中的元素33。5:5:3015:3025:3030:3040:30用join子句進(jìn)行左外部聯(lián)例代碼4-19所示,查詢query1中第二個(gè)from子句則表示在join的分組結(jié)果中進(jìn)行查詢。查詢數(shù)據(jù)源使用DefaultIfEmpty()方法從分組結(jié)果中獲取數(shù)據(jù)。示例代碼4-staticstaticvoidUseLeftJoin({int[]intAry1={5,15,23,30,33,40//創(chuàng)建整數(shù)數(shù)組intAry1int[]intAry2={10,20,30,50,60,70,80//創(chuàng)建整數(shù)數(shù)組intAry2//query1joinvarquery1=fromval1injoinval2inintAry2onval1%5equalsval2%15intoval2Grpfromgrpinval2Grp.DefaultIfEmpty()selectnew{VAL1=val1,VAL2GRP=grpforeachvarobjin { ine("{0}",}}們?cè)趇ntAry2中不存在關(guān)聯(lián)的元素。{{VAL1=5,VAL2GRP=30{VAL1=5,VAL2GRP=60{VAL1=15,VAL2GRP=30{VAL1=15,VAL2GRP=60{VAL1=23,VAL2GRP=0{VAL1=30,VAL2GRP=30{VAL1=30,VAL2GRP=60{VAL1=33,VAL2GRP=0{VAL1=40,VAL2GRP=30{VAL1=40,VAL2GRP=60注意:左外部聯(lián)接和分組聯(lián)接雖然相似但是并非一樣。分組聯(lián)接返回的查詢結(jié)果是一種foreach才能遍歷它的結(jié)果。而左外部聯(lián)接是在分joinfrom子句進(jìn)LINQIEnumerable<T>IQueryable<T>類型對(duì)用查詢結(jié)果數(shù)據(jù)。本節(jié)介紹如何通過(guò)對(duì)象查詢方法使用LINQ。IEnumerable<T>接LINQ中,IEnumerable<T>select子句返回的查詢結(jié)果也是一個(gè)實(shí)現(xiàn)了接口IEnumerable<T>的類。.NET類庫(kù)中,IEnumerabe<T>接口提供了大量與查詢相關(guān)的方法。這些方法實(shí)際上是以擴(kuò)展方法的形式定義,但是由于它的作用類型也為IEnuerable<T>接口,所以使用上和成4.3IEnuerabe<T>接口的主要成員及其功能。4.3IEnumerable<T>主要成 滿足條件返回TRUE,否則返回FALSE以上(含一個(gè))元素滿足條件返回TRUE,否則返回FALSE從表4.3中可以看出,IEnumerable<T>提供的方法包括數(shù)值運(yùn)算(Sum、Min、Max、Average)、元素?cái)?shù)量(Count、LongCount)、取值(First、Last、ElementAt等)、提取注意:IEnuerable<T>IEnumerableIEnumerable接口的所有方法,所以還包括Select()、SelectMany()、Repeat()等方法,在表4.3中并沒有它的使用和IEnumerable<T>類似。本書就不做進(jìn)一步的介紹,可以參看本書關(guān)于LambdaLINQIEnumerable<T>類型的對(duì)象上進(jìn)行操作。所以,LINQ表達(dá)式在真正執(zhí)行時(shí)都轉(zhuǎn)換成具體的函數(shù)調(diào)用。這就要求在LINQ查詢關(guān)鍵字(from、select等)IEnumerable<T>接口的方法之間有一個(gè)對(duì)應(yīng)關(guān)系。該關(guān)系如表4.4所示。4.4查詢表達(dá)式和方法對(duì)IEnumerable<T> from子句指fromintvalin能很少。在實(shí)際開發(fā)中,通過(guò)對(duì)查詢結(jié)果或數(shù)據(jù)源進(jìn)行方法調(diào)用,從而進(jìn)行的查詢操作,這也是本節(jié)的重點(diǎn)。在進(jìn)行方法調(diào)用之前,先要介紹一個(gè)準(zhǔn)備知識(shí)——Lambda表首先,來(lái)看一下示例代碼4-20對(duì)IEnumerable<T>.Where()方法的調(diào)用代碼。其中,Where方法的參數(shù)為“numnum%20Lambda表達(dá)式,它表示只提取能被2整除的數(shù)。示例代碼4-staticstaticvoidLamdaExpExa({int[]intAry={2,4,5,8,9,varquery1=intAry.Where(num=>num%2==0);foreach(varvalinquery1){}//// ine(}Lambda表達(dá)式實(shí)際上是一個(gè)函數(shù)。它包含表達(dá)式和語(yǔ)句,常用于創(chuàng)建委托或表達(dá)式樹類型。所有LambdaLambda運(yùn)算符——=>,該運(yùn)算符讀為“goesto”。Lambda運(yùn)算符的左邊是輸入?yún)?shù)(可能沒有),右邊是表達(dá)式或語(yǔ)句塊。Lambda(inputparameters)=> 括兩個(gè)參數(shù)x和y。(x,y)=>x== Lambda表達(dá)式的參數(shù)都是可變類型的,由編譯器自動(dòng)確定它的具體類型。但有類型。如下所示Lambda表達(dá)式包括xs。其中,xint類型sstring(intx,strings)=>s.Length> Lambda表達(dá)式?jīng)]有參數(shù)時(shí),需要使用空的括號(hào)表示,如下所示。其中,“()”表示()=> 由于Lambda表達(dá)式實(shí)際是函數(shù),它可以賦值到一個(gè)委托,而在IEnumerable<T>的方法中很多都通過(guò)函數(shù)委托來(lái)實(shí)現(xiàn)自定義的運(yùn)算、條件等操作,所以Lambda表達(dá)式在LINQ中被廣泛使用。用Where()方法進(jìn)行篩LINQ查詢中,where子句可以用IEnumerable<T>.Where()方法來(lái)實(shí)現(xiàn)。該方法接收Where()方法。TSource是元素的類型,source參數(shù)是要被查詢的數(shù)據(jù)序列。參數(shù)predicate是Func<TSource,bool>類型的委托,它將序列中的元素(TSource類型)作為參數(shù),publicstaticIEnumerable<TSource>Where<TSource>(publicstaticIEnumerable<TSource>Where<TSource>(thisIEnumerable<TSource>Func<TSource,bool>predicate)publicdelegateTResultFunc<T,示。參數(shù)predicate是Func<TSource,int,bool>類型的委托,它將序列中的元素如果為true,則該元素被選擇作為結(jié)果,否則不被選擇。publicstaticIEnumerable<TSource>Where<TSource>(publicstaticIEnumerable<TSource>Where<TSource>(thisIEnumerable<TSource>Func<TSource,int,bool>predicate)publicdelegateTResultFunc<T1,T2,TResult>(T1在LINQ中,常將Lambda表達(dá)式作為參數(shù)傳遞到Where()方法中,用來(lái)指定一些較為4-21中,query1Where()5整除的所有元素。query2Where()3倍的示例代碼4-staticstaticvoidUseWhereLambda({int[]intAry={1,2,3,5,7,8,10,30,33,44,//創(chuàng)建int數(shù)組intAryvarquery1=intAry.Where(num=>num%5==0);foreachvarvalin {} ine(varquery2=intAry.Where((num,index)=>num>index*3);foreachvarvalin {} ine(}4-21query1intAry5整除的該索引從0開始。query1:5query1:51030query2:1303344注意:Lambda表達(dá)式很難描述時(shí),就需要使用函數(shù)委托來(lái)表示,并且提供一個(gè)獨(dú)立的函數(shù)表示這個(gè)條件判斷。作者建議盡量使用Lambda表達(dá)式表示判斷條件,因?yàn)樗雍?jiǎn)單、直接、易懂。用OrderBy()方法進(jìn)行排publicpublicstaticIOrderedEnumerable<TSource>OrderBy<TSource,TKey>(thisIEnumerable<TSource>source,Func<TSource,TKey>publicstaticIOrderedEnumerable<TSource>OrderByDescending<TSource,thisIEnumerable<TSource>source,Func<TSource,TKey>keySelector)其中,TSource是集合中元素類型,TKeykeySelectorFuncTKey類型的值,該返回4-22所示,其中,Lambda表達(dá)式“val=>val%10”中,val是數(shù)據(jù)集合的元素,val%10表示將val模10的值作為排序依據(jù)。示例代碼4-staticstaticvoidUseOrderBy({int[]intAry={3,-2,5,8,3,4,2,19,20//創(chuàng)建int數(shù)組intAryvarquery1=intAry.OrderBy(val=>val%10);foreachvarvalin {} ine(//quer2intAryval%10從大到小進(jìn)行排序varquery2=intAry.OrderByDescending(val=>val%10);foreachvarvalin {} ine(}4-22query1intAry中的元素按照10的值從小到大排序,查query2intAry中的元素按照模10的值從大到小query1:-2query1:-220233458query2:1985433220使用默認(rèn)的int比較器,所以負(fù)數(shù)小于0。在一些開發(fā)中,以下兩種情況需要使用特定的數(shù)OrderBy()OrderByDescending()方法都提供了一個(gè)接受特定數(shù)據(jù)比較器的方法接口。publicpublicstaticIOrderedEnumerable<TSource>OrderBy<TSource,TKey>(thisIEnumerable<TSource>source,Func<TSource,TKey>keySelector,IComparer<TKey>comparer)publicstaticIOrderedEnumerable<TSource>OrderByDescending<TSource,thisIEnumerable<TSource>source,Func<TSource,TKey>keySelector,IComparer<TKey>comparer)comparerIComparer<TKey>類型的對(duì)象,它提供自定義的數(shù)據(jù)比較器。其中,parerIComparer<int>Compare()int值的新的比較器,且是直接比較int的絕對(duì)值。示例代碼4-////自定義的int類型比較器,實(shí)現(xiàn)IComparer<int> parer:{//x和ypublicintCompare(intx,int{intx1=Math.Abs(x);inty1=Math.Abs(y);if(x1>y1)return1;elseif(x1==y1)return0;return-}//如果|x|>|y|,返回//如果|x|=|y|,返回//如果|x|<|y|,返回-}staticvoidUseOrderByDef({parermc= parer(//創(chuàng)建自定義int類型比較器 int[]intAry={3,-2,5,8,-3,-4,2,-19,20};//創(chuàng)建int數(shù)組intAryvarquery3=intAry.OrderBy(val=>val,mc);foreachvarvalin {}System.Console.WriSystem.Console.Wriine(//query4intAry中所有元素使用自定義比較器從大到小排序varquery4intAry.OrderByDescending(valvalmc);foreachvarvalin {} ine(}query3:-2query3:-223-3-458-19query4:20-1985-43-3-2用Skip()、SkipWhile()跳過(guò)元就需要使用IEnumerable<T>接口的Skip()或SkipWhile()兩個(gè)方法。它們都是用來(lái)跳過(guò)集合中的元素。Skip()只是簡(jiǎn)單的跳過(guò)集合中指定數(shù)量的元素,而SkipWhile()則跳過(guò)集合中滿publicpublicstaticSkip<TSource>(thisIEnumerable<TSource>source,intcount)publicstaticSkipWhile<TSource>(thisIEnumerable<TSource>source,Func<TSource,bool>predicate)publicstaticSkipWhile<TSource>(thisIEnumerable<TSource>Func<TSource,int,bool>其中,參數(shù)count在Skip()中使用,指定要跳過(guò)的元素?cái)?shù)量,被跳過(guò)的元素從集合中第1predicateFuncSkipWhile()中指定要跳過(guò)的元素所滿足的條件。它的第1個(gè)參數(shù)是集合中的元素值,第2個(gè)參數(shù)是該元素的索引。SkipWhile()從集合中第1個(gè)元素開始,使用參數(shù)predicate進(jìn)行計(jì)算。如果返回True,跳過(guò)并繼續(xù)判斷下一個(gè)元素。如果predicate返回False,則停止判斷,返回集合中沒有被4-24Skip()SkipWhile()query1跳過(guò)集合中前面3個(gè)元素,query2則跳過(guò)集合中絕對(duì)值小于10的元素。示例代碼4-staticstaticvoidUseSkip({int[]intAry={3,-2,5,8,-13,-4,12,-19,20varquery1 //查詢query1跳過(guò)intAry中的前面3System.Console.Write("query1:foreachvarvalin {}} ine(varquery2=intAry.SkipWhile(num=>num/10==0);System.Console.Write("query2:");foreachvarvalin {} ine(}絕對(duì)值小于10的元素,即前面4個(gè)元素。query1:query1:8-13-412-19query2:-13-412-19注意:在示例代碼4-24中,雖然intAry的第6個(gè)元素絕對(duì)值也小于10,但是由于第用Take()、TakeWhile()提取元取元素,這兩個(gè)函數(shù)的定義和Skip()類似,如下所示。publicpublicstaticTake<TSource>(thisIEnumerable<TSource>source,intcount)publicstaticTakeWhile<TSource>(thisIEnumerable<TSource>source,Func<TSource,bool>predicate)publicstaticTakeWhile<TSource>(thisIEnumerable<TSource>source,Func<TSource,int,bool>predicate)countTake()中使用,指定要提取的元素?cái)?shù)量,被提取的元素從集合中第1個(gè)元素開始計(jì)數(shù)。參數(shù)predicate是Func類型委托,在TakeWhile()中指定要提取的元素所滿足的條件。它的第1個(gè)參數(shù)是集合中的元素值,第2個(gè)參數(shù)是該元素的索引。提取并繼續(xù)判斷下一個(gè)元素。如果predicateFalse,則停止判斷,返回已經(jīng)提取的元4-25Take()TakeWhile()query1提取集合中前面3個(gè)元素,query2則提取集合中絕對(duì)值小于10的元素。示例代碼4-staticstaticvoidUseTake({int[]intAry={3,-2,5,8,-13,-4,12,-19,20varquery1 //查詢query1提取intAry中的前面3System.Console.Write("query1:foreachvarvalin {{} ine(varquery2=intAry.TakeWhile(num=>num/10==0);System.Console.Write("query2:");foreachvarvalin {} ine(}絕對(duì)值小于10的元素,即前面4個(gè)元素。query1:query1:3-2query2:3-25注意:在示例代碼4-25中,雖然intAry的第6個(gè)元素絕對(duì)值也小于10,但是由于第用Max()等對(duì)元素進(jìn)行數(shù)值計(jì)Sum()這些數(shù)值計(jì)算函數(shù),都包括13個(gè)重載版本,最簡(jiǎn)單的一個(gè)版本不接收任何參數(shù),此時(shí)參與計(jì)算的元素類型必須具有默認(rèn)的數(shù)值運(yùn)算支持。其中,Max()Min()都需要類型具intfloat等數(shù)值類型、string字符串類型、枚舉類型等。而Sum()Average()int、float等數(shù)值類型,從而intArystrAry示例代碼4-staticstaticvoidUseValueCalc({int[]intAry={1,2,3,4,5,6,7,8,9,varintMax=intAry.Max(); //intAry中的最大值varintMin=intAry.Min(); //intAry中的最小值varintAverage=intAry.Average();//intAry中元素的平均值varintSum=intAry.Sum( //intAry中元素的累加 ine("intAry'smax={0},min={1},average={2},sum={3}",intMax,intMin,intAverage,intSum);//創(chuàng)建string數(shù)組strArystring[]strAry={" o"," othanksalibabastreetvarstrMax=strAry.Max(); //strAry中的最大值varstrMinstrAry.Min //strAry ine("strAry'smax={0},min={1}",strMax,}示例代碼4-26的輸出如下所示。從輸出結(jié)果中可以看出,雖然intAry的所有元素都為intintAveragefloat類型,從而可以保存小數(shù)。而字符串大intAry'sintAry'smax=10,min=1,average=5.5,sum=55strAry'smax=thanks,min=alibaba能對(duì)strAry進(jìn)行求和或平均操作,即代碼strAry.Sum()是錯(cuò)誤的語(yǔ)法。4-27Lambda表達(dá)式“str=>str.Length”提供一個(gè)傳入字符串,返strArySum()、Average()操作。其中,strMax是所strAverage是所有字符串長(zhǎng)度的平均值。示例代碼4-staticstaticvoidUseValueCalc2({//創(chuàng)建string數(shù)組strArystring[]strAry={" o","hel","thanks","alibaba","street"};varstrMax=strAry.Max(str=>str.Length);//strAryvarstrMin=strAry.Min(str=>//strAry ine("strAry'smax={0},min={1}",strMax,varstrSum=strAry.Sum(str=>//strAryvarstrAverage=strAry.Average(str=>//strAry ine("strAry'ssum={0},average={1}",strSum,}示例代碼4- 的輸出如下所示。其中,Max()、Min()操作由于使用了參數(shù),所以輸strAry'smax=7,min=3strAry'sstrAry'smax=7,min=3strAry'ssum=27,average=5.4技巧:實(shí)際開發(fā)中,可以按照某種特定規(guī)則將非數(shù)值類型數(shù)據(jù)映射到數(shù)值類型,然后使用Distinct()消除集合中相等的元LINQEnurabe<>Dstinct()方法完成。Distinc()方法包括一個(gè)不帶參數(shù)的版本。它使用默認(rèn)的相等比較器對(duì)集合中的元素進(jìn)行比較,定義如下:publicstaticIEnumerable<TSource>Distinct<TSource>(publicstaticIEnumerable<TSource>Distinct<TSource>(thisIEnumerable<TSource>4-28中,intAryint數(shù)組,它包含多個(gè)相等元素,查詢query1通過(guò)Distinct()方法消除所有重復(fù)的元素。示例代碼4-staticstaticvoidUseDistinctSimple({int[]intAry={1,3,6,9,1,3,9,10,2,5,3,varquery1=intAry.Distinct(//查詢query1對(duì)intAry中的元素進(jìn)行消除System.Console.Write("query1:query1foreach(varitemin{}}4-28的輸出如下所示。從輸出結(jié)果中可以看出,相等的元素只出現(xiàn)了一次,query1:1369102 int之類的簡(jiǎn)單類型,甚至該類型根本不存在默認(rèn)的相等比較器時(shí),要對(duì)publicstaticIEnumerable<TSource>Distinct<TSource>(publicstaticIEnumerable<TSource>Distinct<TSource>(thisIEnumerable<TSource> parer<TSource> 和boolEquals(Tx,Ty)intboolEquals(Tx,Ty)intGetHashCode(Tobj)其中,T是具體的元素類型。Distinct()4.2所示的流程圖進(jìn)行元素重復(fù)性4.2Distinct()方法執(zhí)行流程判斷,只有兩個(gè)元素的哈希碼相等,而且在Equals()方法中也判斷為相等時(shí)才算是重復(fù)在示例代碼4-29中, parer<string>。在GetHashCode()中將字符串長(zhǎng)度作為字符串的長(zhǎng)示例代碼4-{parer//實(shí)現(xiàn)Equals(){parer<string>.Equals(stringx,string//如果兩個(gè)字符傳的第一個(gè)字符相等,則返回truereturnx.Substring(0,1y.Substring(0,1);}//實(shí)現(xiàn)GetHashCode()publicintGetHashCode(string{return }}static plex({string[]strAry={"hel","how","parermcStr=varquery2=strAry.Distinct(mcStr);System.Console.Write("query2:");foreachvarvalin {} ine(}示例代碼4-29的輸出如下所示。由how和hel具有相同的字符串長(zhǎng)度和相同的首字query2: otower 技巧:在編寫自定義的相等比較器時(shí),將HashCode和Equals()看成是兩個(gè)具有主次關(guān)系的用Concat()連接兩個(gè)集在LINQ中,還可以通過(guò)IEnumerable<T>的Concat()方法將兩個(gè)集合中的元素首尾相連,從而構(gòu)成一個(gè)新的IEnumerable<T>對(duì)象。Concat()方法定義如下:publicstaticIEnumerable<TSource>Concat<TSource>(publicstaticIEnumerable<TSource>Concat<T

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論