[C#]C#學習筆記-LINQ
C#學習筆記-LINQ
羅朝輝(http://www.rzrgm.cn/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()。
浙公網安備 33010602011771號