一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

到現(xiàn)在為止你還未觸碰LINQ,那進(jìn)來吧 —— LINQ入門(中篇)

 xyjackxjw 2013-04-27

到現(xiàn)在為止你還未觸碰LINQ,那進(jìn)來吧 —— LINQ入門(中篇)

前 言

  在上篇中簡單的分享了LINQ的基礎(chǔ)概念及基礎(chǔ)語法,如果沒有閱讀過上篇的朋友可以點(diǎn)擊這里。感謝大家的支持,本篇我們將更進(jìn)一步的學(xué)習(xí)LINQ的一些相關(guān)特性及應(yīng)用方法。廢話不多說,請往下閱讀吧。

延遲加載

  在上篇中簡單的和大家提到了LINQ具有一個(gè)很有意思的特性那就是“延遲加載”(或“延遲計(jì)算”),什么是延遲加載呢?先看來自官方的描述:延遲執(zhí)行意味著表達(dá)式的計(jì)算延遲,直到真正需要它的實(shí)現(xiàn)值為止。是不是覺得有點(diǎn)生澀難理解呢?按照我個(gè)人的理解通俗的講就是,每當(dāng)我們編寫好一段LINQ表達(dá)式時(shí),此時(shí)這個(gè)表達(dá)式所代表的序列變量僅僅只是一個(gè)代理,編譯器在執(zhí)行編譯時(shí)根本就不鳥這段代碼,檢查完語法正確性后直接跳過,直到代碼在編譯器動(dòng)態(tài)運(yùn)行序列變量在其他代碼塊被調(diào)用時(shí),它所代理的linq表達(dá)式才會(huì)執(zhí)行。啊~~看到這里你是不是要暈了,到底要怎么理解啊,無廢話上代碼:

 

復(fù)制代碼
 1 // 已知一個(gè)序列
 2 var array = new int[] {1, 2, 3};
 3 
 4 // 編寫一段LINQ表達(dá)式獲得一個(gè)序列變量query
 5 // 注意,這個(gè)變量僅僅是一個(gè)代理,在執(zhí)行編譯的時(shí)候,編譯器檢查完
 6 // 該代碼的正確性后直接跳過,不再理會(huì)
 7 var query = from arr in array
 8             where arr > 1
 9             select arr;
10 
11 // 調(diào)用上述序列變量query,此時(shí)上述的LINQ表達(dá)才會(huì)執(zhí)行。注意此時(shí)已是在
12 // 編譯器Runtime 的情況下執(zhí)行
13 foreach(var q in query)
14     Console.WriteLine(q.ToString());
復(fù)制代碼

 

如果你覺得上述例子不能讓你有個(gè)深刻的理解,那么請看來自MSDN的例子

復(fù)制代碼
 1 public static class LocalExtensions
 2 {
 3     public static IEnumerable<string>
 4       ConvertCollectionToUpperCase(this IEnumerable<string> source)
 5     {
 6         foreach (string str in source)
 7         {
 8             Console.WriteLine("ToUpper: source {0}", str);
 9             yield return str.ToUpper();
10         }
11     }
12 }
13 
14 class Program
15 {
16     static void Main(string[] args)
17     {
18         string[] stringArray = { "abc", "def", "ghi" };
19         // 這里方法 ConvertCollectionToUpperCase 是不會(huì)在編譯時(shí)進(jìn)行調(diào)用核查的,直到下面的foreach調(diào)用變量 q 此方法才會(huì)執(zhí)行
20         var q = from str in stringArray.ConvertCollectionToUpperCase()
21                 select str;
22 
23         foreach (string str in q)
24             Console.WriteLine("Main: str {0}", str);
25     }
}
復(fù)制代碼

注意,ConvertCollectionToUpperCase 是一個(gè)靜態(tài)擴(kuò)展方法,后續(xù)講解,如果你對.net 2.0 的 yeild 不熟悉的網(wǎng)上查閱吧,這里就不做介紹了。

復(fù)制代碼
// 輸出結(jié)果
// ToUpper: source abc
// Main: str ABC
// ToUpper: source def
// Main: str DEF
// ToUpper: source ghi
// Main: str GHI
復(fù)制代碼

  小結(jié),延遲加載有好也有壞,由于是在Runtime的情況下執(zhí)行序列,所以就容易造成未知異常,斷點(diǎn)打錯(cuò)等等,所以編碼LINQ是一定要考慮到它的這個(gè)特性。

lambda 表達(dá)式

  了解完延遲加載后,那么現(xiàn)在我們需要簡單的學(xué)習(xí)一下.net 3.5 給我們帶來的新特性lambda表達(dá)式,在上篇的評論中,有園友問lambda和linq有什么關(guān)系,在這里其實(shí)他們沒有任何關(guān)系,是完全不同的東西,但是我們?yōu)槭裁匆莆账??因?yàn)樵诤罄m(xù)的學(xué)習(xí)中會(huì)使用大量的lambda表達(dá),他可以使我們的代碼更優(yōu)雅更有可讀性,大大提高了我們的編碼效率。

  那么在學(xué)習(xí)lambda之前,先來回顧一下.net 2.0給我們帶來的委托 delegate ,這個(gè)你一定不會(huì)感到陌生吧,而且一定會(huì)常用他。對于委托這里就不做詳細(xì)的介紹了,要復(fù)習(xí)委托的在網(wǎng)上查閱吧。通過委托,我們可以得到一個(gè)東西“匿名方法”。咦,是不是覺得很眼熟,呵呵,用代碼來加深回憶吧

public delegate void SomeDelegate1;
public delegate void SomeDelegate2(arg 1, arg 2);

// 匿名方法
SomeDelegate1 del1 += delegate() {...};
SomeDelegate2 del2 += delegate(arg1, arg2) {...}

上面的代碼中我們看到在.net 2.0時(shí)代,我們可以通過delegate創(chuàng)建匿名方法,提高編碼的靈活性,那么lambda和這個(gè)有什么關(guān)系呢,lambda對匿名方法進(jìn)行了升華??创a:

public delegate void SomeDelegate1;
public delegate void SomeDelegate2(arg 1, arg 2);

// 匿名方法
SomeDelegate1 del1 += () => {...};
SomeDelegate2 del2 += (arg1, arg2) => {...}

  呵呵,是不是覺得有點(diǎn)不可思議呢,言歸正傳什么是lambda表達(dá)式呢,來自官方的定義:“Lambda 表達(dá)式”是一個(gè)匿名函數(shù),它可以包含表達(dá)式和語句,并且可用于創(chuàng)建委托或表達(dá)式樹類型。所有 Lambda 表達(dá)式都使用 Lambda 運(yùn)算符 =>,該運(yùn)算符讀為“goes to”。 該 Lambda 運(yùn)算符的左邊是輸入?yún)?shù)(如果有),右邊包含表達(dá)式或語句塊。 Lambda 表達(dá)式 x => x * x 讀作“x goes to x times x”。在定義里提到了表達(dá)式樹,這是高階晉級的話題,這里就不做討論了,我們先把精力放在入門與實(shí)戰(zhàn)應(yīng)用上。

常規(guī)的lambda表達(dá)式如下:

 

(parameters) => {expression}

 

當(dāng)指定的委托類型沒有參數(shù)是表達(dá)式可以如下

 

() => {expression} 例:() => {/*執(zhí)行某些方法*/}

 

如果表達(dá)右側(cè)花括號里只有一個(gè)表達(dá)例如一元表達(dá)式,二元表達(dá)式等等,又或者是一個(gè)方法時(shí)那么花括號可以省略如下:

 (x) => x; // 最簡表達(dá)式

 (x, y) => x == y;

 () => SomeMethod();

 注意,如果右側(cè)的表達(dá)式存在花括號"{}",而且委托是具有返回類型的,那么表達(dá)式必須帶上 return 關(guān)鍵字,如下:

(x, y) => {return x == y;};

到此我們已對lambad 表達(dá)式有了一定的掌握與了解。那么我們擴(kuò)展一下,在.net 3.5中,ms 給我們提供了兩個(gè)泛型委托 分別是 Fun<T> 和 Action <T> 他們可以幫助我們省去了返回創(chuàng)建常用委托的麻煩,提高編碼效率。

共同點(diǎn):它們至多提供委托傳遞6個(gè)參數(shù)(任意類型);

不同點(diǎn):Fun 要求必須具有返回類型,而Action則必須不返回類型,規(guī)定返回 void

示例:

Fun<int, int, bool> fun = (a, b) => a==b;

Action<string> action = (p) => Console.Write(p);

小結(jié),lambda 對我個(gè)人而言是個(gè)又愛又恨啊,不過愛多一點(diǎn),它使我們寫更少的代碼做更多的事,但是在調(diào)試時(shí)一旦修改表達(dá)式內(nèi)容,那么當(dāng)前調(diào)試要么停止,要么重新開始,ms要是在這方面做得更完美些就好啦。不過它也間接提醒我們要有好的編碼設(shè)計(jì)思維。

靜態(tài)擴(kuò)展方法

  說完lambda,那么我們就進(jìn)一步了解一下.net 3.5的另一個(gè)新特性“靜態(tài)擴(kuò)展方法”,什么是靜態(tài)擴(kuò)展方法呢,官方定義:擴(kuò)展方法使您能夠向現(xiàn)有類型“添加”方法,而無需創(chuàng)建新的派生類型、重新編譯或以其他方式修改原始類型。 擴(kuò)展方法是一種特殊的靜態(tài)方法,但可以像擴(kuò)展類型上的實(shí)例方法一樣進(jìn)行調(diào)用。簡單的說就是我們可以向一個(gè)已知的類型在不通過繼承,復(fù)寫等操作的情況下添加一個(gè)方法,以便類型的實(shí)例可以直接使用該方法。示例如下:

 

復(fù)制代碼
static class A
{
    // 這里的p1,p2 僅作為示例,實(shí)際中我們不一定需要
    public static int ExtendMethod1(this string input,string p1, string p2)
    {
         return int.Parse(input + p1 + p2);
    }

     // 泛型方法
     public static TOutput, ExtendMethod2<TOutput>(this object obj);
     {
           return (TOutput)obj;
     }
}

class B
{
  void Main()
{
var a = "1";
var result = a.ExtendMethod1("2","3");
// result:123
}
}
復(fù)制代碼

 

注意,方法的 static 是必須的,而且需在靜態(tài)類里。第一個(gè)參數(shù) this 是必須的,緊跟著 this 后面的需要擴(kuò)展的類型實(shí)例參數(shù),也是必須的。至于后面的方法調(diào)用傳遞參數(shù)就因個(gè)人所需了。

  既然我們學(xué)習(xí)了靜態(tài)擴(kuò)展方法,那么它和LINQ又有什么關(guān)系呢?在System.Linq的命名空間中提供了大量的靜態(tài)擴(kuò)展方法,這些靜態(tài)方法本身就對linq表達(dá)式的封裝,這樣我們就可以省去了編寫簡單的linq表達(dá)式的步驟。如下:

 

var array = new int[]{1,2,3,4,5};

var query1 = from arr in array
             select arr;

var query2 = array.Select(e => e);

 

上面的示例中 query1 和 query2 是等價(jià)的,通過 query2  我們是不是又可以偷懶了很多,呵呵。

再來點(diǎn)帶where的

復(fù)制代碼
var array = new int[]{1,2,3,4,5};

var query1 = from arr in array
             where arr > 2
             select arr;

var query2 = array.Where(e => e > 2);
復(fù)制代碼

再來一個(gè)復(fù)合型的

var array = new int[]{1,2,3,4,5};

var max = (from arr in array.Where(e => e > 2)
           select arr).Max();

是不是覺得很cool。由于篇幅的關(guān)系在這里就不逐一的去接受這些靜態(tài)方法了,下面是一些常用的靜態(tài)方法列表,感興趣的去MSDN查閱詳細(xì)吧。

Aggregate , All , Any , AsEnumerable , Average , Cast , Concat , Contains, Count, DefaultIfEmpty , Distinct , ElementAt, ElementAtOrDefault ,Empty , Except , First, FirstOrDefault , GroupBy , GroupJoin , Intersect , Join , Last , LastOrDefault , LongCount , Max , Min , OfType ,OrderBy ,OrderByDescending , Range , Repeat , Reverse , Select , SelectMany , SequenceEqual , Single , SingleOrDefault , Skip , SkipWhile , Sum ,Take, TakeWhile , ThenBy , ThenByDescending , ToArray , ToDictionary , ToList, ToLookup, Union,Where

Cast<T> 和 OfType<T> 靜態(tài)擴(kuò)展方法

  在最后我們還是要注意兩個(gè)常用的靜態(tài)方法Cast<T>, OfType<T> 。它們的共同點(diǎn)是都能把非IEnumerable<T> 類型的集合轉(zhuǎn)換成IEnumerable<T>類型,然后再

進(jìn)行LINQ操作,如下

復(fù)制代碼
var dt = new DataTable();
dt.Columsn.Add("A", typeof(int));

var newRow1 = dt.NewRow();
newRow1["A"] = 1;

var newRow2 = dt.NewRow();
newRow2["A"] = 2;

dt.Rows.Add(newRow1);
dt.Rows.Add(newRow2);

var query1 = dt.Rows.Cast<DataRow>().Select(e=>(int)e["A"]);
var query2 = dt.Rows.OfType<DataRow>().Select(e=>(int)e["A"]);
復(fù)制代碼

這樣我們就可以得到看上去兩個(gè)相同的序列,在這里要注意:MSDN上的說明存在誤導(dǎo),MSDN對于OfType<T>的解釋存在偏差,實(shí)際上經(jīng)本人反復(fù)敲代碼驗(yàn)證,得到的結(jié)論是,Cast對序列進(jìn)行強(qiáng)制轉(zhuǎn)換,一旦轉(zhuǎn)換不成功則拋出異常。OfType則是一旦轉(zhuǎn)換不成功,則不會(huì)拋出異常,但是將會(huì)得到一個(gè)空序列。見下面代碼:

復(fù)制代碼
var arr1 = new string[] { "1","2","test" };
var arr2 = arr1.Cast<int>();
var arr3 = arr1.OfType<int>();

//通過Cast轉(zhuǎn)換,則會(huì)拋出異常
foreach (var i in arr2)
     Console.WriteLine(i.ToString());

//通過OfType轉(zhuǎn)換,有異常但是不會(huì)拋出并得到一個(gè)空序列
foreach (var i in arr3)
      Console.WriteLine(i.ToString());

Console.Read();
復(fù)制代碼

 

總 結(jié)

  本文到此,我們已對LINQ涉及的應(yīng)用有了進(jìn)一步的了解。學(xué)習(xí)什么是linq的延遲加載,lambda和linq是否有曖昧關(guān)系。以及靜態(tài)擴(kuò)展方法對linq的輔助作用。也許你會(huì)問既然可以用靜態(tài)擴(kuò)展方法替代編寫linq,那么二者怎么擇取呢,據(jù)磚家叫獸提議我們應(yīng)該先以linq命名空間下的靜態(tài)擴(kuò)展方法為主,實(shí)在是很復(fù)雜的linq表達(dá)式,我們再考慮使用linq本身的表達(dá)式編寫。后續(xù)我們將分享學(xué)習(xí)LINQ更貼近實(shí)戰(zhàn)應(yīng)用的知識,linq to dataset, linq to xml, linq to sql, linq to entities.

  感謝您的閱讀,如果有說得不對的地方請指正。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    男人和女人草逼免费视频| 午夜国产福利在线播放| 欧洲一级片一区二区三区| 丰满人妻少妇精品一区二区三区| 丰满少妇被猛烈撞击在线视频 | 人妻中文一区二区三区| 成在线人免费视频一区二区| 亚洲熟女熟妇乱色一区| 日韩一区二区三区在线欧洲| 加勒比系列一区二区在线观看| 少妇高潮呻吟浪语91| 亚洲欧美日韩在线中文字幕| 精品久久av一二三区| 欧美日韩精品综合在线| 国产精品久久精品国产| 黄片美女在线免费观看| 国产精品福利一二三区| 夫妻性生活一级黄色录像| 精品久久av一二三区| 爽到高潮嗷嗷叫之在现观看| 欧洲自拍偷拍一区二区| 最近中文字幕高清中文字幕无| 国产精品视频一区二区秋霞| 丰满的人妻一区二区三区| 亚洲最新中文字幕一区| 国产一区欧美一区日本道| 亚洲一区二区三区在线中文字幕| 国产精品久久精品国产| 熟妇人妻av中文字幕老熟妇| 亚洲欧洲成人精品香蕉网| 丰满人妻熟妇乱又伦精另类视频 | 日本精品视频一二三区| 熟女体下毛荫荫黑森林自拍| 国产精品不卡一区二区三区四区| 精品少妇人妻av一区二区蜜桃| 人人妻在人人看人人澡| 日本av一区二区不卡| 日韩女优视频国产一区| 亚洲欧美日韩中文字幕二欧美| 国产又黄又爽又粗视频在线| 中文字幕一区二区三区大片|