C#學習筆記-LINQ
羅朝輝(http://www.cnblogs.com/kesalin/)
《C#與.NET進階程式設計》讀書筆記
1,LINQ(語言級整合查詢)的意圖是提供一種統一且對稱的方式,讓程式員在廣義的資料上得到和操作資料。通過使用LINQ,我們能夠在C#程式設計語言內直接建立被稱為查詢運算式的實體。這些查詢運算式是基於許多查詢運算子的,而且有意設計成類似SQL運算式的,但它可以被用來與多種資料互動,而不局限於關聯式資料庫。具體來說,LINQ允許查詢運算式以統一的方式來操作任何通過擴充方法直接或間接實現了 IEnumerable<T>介面的對象,關聯式資料庫,Dataset或XML文檔。
static void QueryOverString()
{
string[] Games = {"Morrowind", "BioShock", "Half Life 2", "The Darkness"};
// 建造一個查詢運算式,來代表數組中多於6個字母的項。
IEnumerable<string> subSet = form g in Games where g.Length > 6 orderby g select g;
// 輸出結果
foreach (string s in subset)
Console.WriteLine("Item: {0}", s);
}
2,LINQ運算式是強型別和可擴充的。在上面的例子中 subSet 的類型是確定的,即便我們是使用 var 來修飾它。LINQ運算式在我們迭代內容之前,不會真正進行運算,這個特性被叫做順延強制,該特性的好處在於可以為相同的容器多次應用相同的LINQ查詢,而始終可以獲得最新的最好的結果。如果要立即執行的話,可以調用由Enumerable類型定義的許多擴充方法來完成,如:ToArray,ToDictionary,TKey以及ToList等擴充方法,它們允許我們以強型別容器來捕獲LINQ查詢結果。
3,LINQ的查詢運算子是設計用於任何實現了IEnumerable<T>介面的類型的,無論是直接地還是通過擴充方法間接實現的。但System.Collections中傳統的非泛型容器類卻沒有這些結構,我們可以用泛型Enumerable.OfType<T>方法來對包含在這些非泛型集合裡的資料進行迭代操作。因為非泛型型別可以包含任何類型的項,所以我們還可以通過OfType<T>來過濾調與需要迭代操作所指定類型不同的元素。
ArrayList strs = new ArrayList() {"one", "two", "three"};
// 把ArrayList轉換成一個相容於IEnumerable<T>的類型
IEnumerable<string> strEnum = strs.OfType<string>();
// 建立查詢運算式
var longStr = from str in strs where str.Length > 2 select str;
4,上面的例子中查詢運算子(如:from,in,where,orderby和select),C#編譯器實際上是把這些標記翻譯成了對System.Linq.Enumerable類型的各種方法的調用(也可能是其他類型,這取決於LINQ查詢)。實際上,Enumerable的許多方法的原型都是把委託昨晚參數,特別是許多方法都要求一個定義在System.Core.dll的System命名空間中類型為Func<>的泛型委派作為參數,該委託的代理最多可以接受4個輸入參數。我們可以手工建立一個新的委託類型,編寫所需要的目標方法,並使用C#的匿名方法,或者也可以定義一個合適的Lambda運算式來替代查詢運算式。如上例可改寫為:
ArrayList strs = new ArrayList() {"one", "two", "three"};
// 把ArrayList轉換成一個相容於IEnumerable<T>的類型
IEnumerable<string> strEnum = strs.OfType<string>();
// 建立查詢運算式
var longStr = strs.Where(str => str.Length > 2).Select(str => str);
或者
ArrayList strs = new ArrayList() {"one", "two", "three"};
// 把ArrayList轉換成一個相容於IEnumerable<T>的類型
IEnumerable<string> strEnum = strs.OfType<string>();
// 使用 Enumerable 類型和匿名方法來建立查詢運算式
// 使用匿名方法建立所需的Func<>委託
Func<string, bool> filter = delegate(string str) { return str.Length > 2;};
Func<string, string> itemToProcess = delegate(string s) { return s;};
// 把委託傳遞給Enumerable的方法
var subset = strs.Where(filter).Select(itemToProcess);
5,LINQ查詢運算子有:from,in,where,select,join,on,equals,into,orderby,ascending,descending,group,by等。此外,Enumerable類型還提供了一套沒有直接的查詢運算子簡化符號,而且是以擴充方法呈現的方法,可以調用這些泛型方法以各種方式來對一個結果集進行轉換(Reverse<>(), ToArray<>(), ToList<>()等);或對結果集進行操作(Distinct<>(), Union<>(), Intersect<>()等);或對結果集進行彙總操作(Count<>(), Sum<>(), Min<>(), Max<>()等)。比如:
// 擷取從查詢獲得的總數
int numb = (from str in strs where str.Length > 2).Count<string>();
6,我們也可以從現有的資料來源投影出新的資料形式,具體做法是定義一個select語句,通過匿名型別動態地形成新的類型。
class Car
{
public string PetName = string.Empty;
public string Color = string.Empty;
}
Car[] myCars = new [] {
new Car { PetName = "Henry", Color = "White"},
new Car { PetName = "Daisy", Color = "Tan"},
new Car { PetName = "Mary", Color = "Black"},
};
// 查詢子集
var onlyBlack = from c in myCars where c.Color = "Black" select c;
// 投影新資料類型
var names = from c in myCars select new {c.PetName};
foreach (var o in names)
Console.WriteLine(o.PetName);
使用投影技術有一個問題,我們不能把投影出的新資料當作傳回值,因為它是隱式類型的(var names),因為我們必須把它轉換為強型別資料(如Array)再返回,如果我們要返回上例中的names,我們可使用 return names.ToArray()。