LINQ基礎(一)

LINQ介紹

   在討論LINQ之前,首先要了解一下序列,它是LINQ的基礎。序列就像是數據項的傳送帶---你每次只能獲取到它們一個,直到你不再想獲取數據,或者序列中沒有數據了。它通過IEnumerable和Ienumerable<T>接口進行封裝。
   序列和其他集合數據結構(比如列表和數組)之間最大的區別就是,當你從序列中讀取數據的時候,通常不知道還有多少數據項等待讀取,或者不能訪問任意的數據項---只能是當前的這個。實際上,一些序列永遠不會結束:例如,你能輕易地擁有一個隨機數的無限序列。列表和數組也能作爲序列,因爲List<T>實現了Ienumerable<T>---不過,反過來並不總是可行。比如,你不能擁有一個無限的數組或列表。
   接下來通過一個簡單的例子來分析一下:
var adultNames= from person in people
                where person.Age>=18
                select person.Name;
   上面這個操作首先會從people中 得到所有的person對象,然後根據where後面的條件得到年齡至少爲18的所有person對象,最後從中獲取年齡至少爲18歲的人的名字列表。

LINQ的延遲處理和流處理

   上面的查詢表達式被創建的時候,不會處理任何數據,也不會訪問原始的人員列表。而是在內存中生成了這個查詢的表達形式。判斷是否爲成人的謂詞,以及人到人名的轉換,都是通過委託實例來表示的。只有在訪問結果Ienumerable<string>的第一個元素的時候,整個車輪纔開始向前滾動。 LINQ的這個特點稱爲延遲執行。在最終結果的第一個元素被訪問的時候,Select轉換纔會爲它的第一個元素調用Where轉換。而Where轉換會訪問列表中的第一個元素,檢查這個謂詞是否匹配,並把這個元素返回給Select。最後,依次提取出名稱作爲結果返回。

LINQ的簡單使用

  聲明一個數據序列的數據源:
 from element in source
   element只是一個標識符,它前面可以放置一個類型名稱。大多數情況下,你都不需要類型名稱。source是一個普通的表達式。
   在第一個子句出現之後,許多不同的事情會發生,不過遲早都會以一個select子句或者group子句來結束。select子句的語法入下:
 select expression
   select 子句被稱爲投影。group子句下面再介紹。
   在LINQ中,從數據源中根據條件獲取數據會寫成:from ... Where...select而不會像SQL中的select...from...where。

2、Cast、OfType和顯示類型的範圍變量

   Cast和OfType操作符很相似:都可以處理任意非類型化的序列(它們是非泛型IEnumerable類的擴展方法),並返回強類型的序列。Cast通過把每個元素都轉換爲目標類型(遇到不是正確類型的任何元素的時候,就會出錯)來處理,而OfType首先進行一個測試,以跳過任何具有錯誤類型的元素。例如:
  ArrayList list=new ArrayList{"First","Second","Third"};
  Ienumerable<string> strings=list.Cast<String>();
  foreach(string item in strings)
  {
     Consolt.WriteLine(item);
  }

  list=new ArrayList{1,"not an int",2,3};
  Ienumerable<int> ints=list.OfType<int>();
  foreach(int item in ints)
  {
    Console.WriteLint(item);
  }
   第一個列表只包含字符串,所以可以放心使用Cast<string>來獲得一個字符串序列。第2個列表包含混雜的內容,爲了從中只獲取整數,我們只能使用OfType<int>。如果我們在第二個列表上使用Cast<int>時,在嘗試將“not an int”轉換成int的時候,就會拋出一個異常。不過,這個異常只會發生在打印出“1”之後---兩個操作符都對數據進行流處理,在獲取元素的時候纔對其進行轉換。
   在原來的.NET 3.5中,允許執行的轉換很多,但是.NET 3.5 SP1修改了Cast的行爲,只允許進行一致性轉換。例如:在.NET3.5 中允許對List<short>使用Cast<int>將每個short轉換成int,而在SP1中,這樣將會拋出異常。如果需要引用轉換和拆箱轉換(或非操作的一致性轉換)之外的轉換,可以使用select投影。OfType也只能執行這些轉換,不過失敗時它不會拋出異常。下面使用顯示類型的範圍變量來自動調用Cast:
ArrayList list=new ArrayList{"First","second","third"};
var strings=from string entry in list
            select entry.Substring(0,3);
foreach(string start in strings)
{
    Console.WriteLine(start);
}
   上面的代碼將輸出:Fir 、sec、thi,上面的代碼通過轉譯過的查詢表達式如下:
list.Cast<string>().Select(entry=>entry.Substring(0,3));
   沒有這個類型轉換,我們根本不能調用Select,因爲該擴展方法只用於Ienumerable<T>而不能用於IEnumrable。即使使用了強類型集合,你可能還是想使用顯示類型的範圍變量。

總結

對上面的代碼總結來說:
1.LINQ以數據序列爲基礎,在任何可能的地方都進行流處理。
2.創建一個查詢並不會立即執行它:大部分操作都會延遲執行。
3.C#3的查詢表達式包括一個把表達式轉換爲普通C#代碼的預處理階段,接着使用類型推斷、重載、Lambda表達式等這些常規的規則來恰當地對轉換後的代碼進行編譯。
4.在查詢表達式中聲明的變量的作用:它們僅僅是範圍變量,通過它們你可以在查詢表達式內部一致地引用數據。

來自:深入理解C#(第三版)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章