(一)LINQ概述
語言集成查詢(Language Integrated Query,LINQ)在C#編程語言中繼承了查詢語法,可以用相同的語法訪問不同的數據源。
1、LINQ查詢
var query = from r in Formula1.GetChampions() where r.Country == "Brazil" orderby r.Wins descending select r;
這是一個LINQ查詢,子句from、where、orderby、descending和select都是這個查詢中預定義的關鍵字。
2、擴展方法
擴展方法在靜態類中聲明,定義一個靜態方法,其中第一個參數定義了它擴展的類型。
例子:
public static void WriteWithTime(this string message) { Console.WriteLine(message + "," + DateTime.Now.ToString("yyyy-MM-dd")); }
為了和一般的靜態方法進行區分,擴展方法還需要對第一個參數使用this關鍵字。
現在可以使用帶string類型的WriteWithTime()方法了。
例子:
string message = "test txt"; message.WriteWithTime();
定義LINQ擴展方法的一個類是System.Linq名稱空間中的Enumerable。
例子:
List<int> intList = new List<int>() { 1, 2, 3, 4, 5 }; var maxIntList = intList.Where(i => i > 4);
這裡使用Where擴展方法獲取大於4的值。
3、推遲查詢的執行
在運行期間定義查詢表達式時,查詢就不會運行。查詢會在迭代數據項時進行。
例子:
List<int> intList = new List<int>() { 1, 2, 3, 4, 5 }; var maxIntList = intList.Where(i => i > 4); foreach (var item in maxIntList) { Console.WriteLine(item); } intList.Add(6); foreach (var item in maxIntList) { Console.WriteLine(item); }
運行以上代碼,結果如下:
需要注意的是,每次在迭代中使用查詢時,都會調用擴展方法(可以檢測出數據源中的變化)。但調用擴展方法ToArray()、ToList()可以改變這個操作。
例子:
List<int> intList = new List<int>() { 1, 2, 3, 4, 5 }; var maxIntList = intList.Where(i => i > 4).ToList();//調用ToList()方法 foreach (var item in maxIntList) { Console.WriteLine(item); } intList.Add(6); foreach (var item in maxIntList) { Console.WriteLine(item); }
運行以上代碼,結果如下:
(二)標准的查詢操作符
參考:http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html
(三)並行LINQ
1、並行查詢
例子:
var data = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 }; var res = data.AsParallel().Where(d => d > 2);
調用AsParaller()方法進行LINQ並行查詢。
2、分區器
AsParallel()方法不僅擴展了IEnumerable<T>接口,還擴展了System.Collection.Concurrent名稱空間的Partitioner類。
例子
var data = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 }; var result = Partitioner.Create(data, true).AsParallel().Where(d => d > 2);
使用Create()方法手工創建一個分區器。
3、取消
.NET提供了一種標准方式,來取消長時間運行的任務,這也適用於並行LINQ。
例子:
var data = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 }; var cts = new CancellationTokenSource(); Task.Factory.StartNew(()=> { try { var resu = data.AsParallel().WithCancellation(cts.Token).Where(d => d > 2); Console.WriteLine("查詢結束"); } catch (OperationCanceledException ex) { Console.WriteLine(ex.Message); throw; } }); Console.WriteLine("查詢開始"); Console.WriteLine("取消?"); string input = Console.ReadLine(); if (input.ToLower().Equals("y")) { cts.Cancel(); }
給並行查詢處添加WithCancellation()方法,參數為CancellationToken令牌為參數。當取消查詢時會拋出OperationCanceledException類型的異常,捕捉異常後可以使用Cancel()方法取消查詢任務。
(四)表達式樹
C#編譯器根據類型給lambda表達式定義不同的行為,當類型為Expression<T>,編譯器就從lambda表達式中創建一個表達式樹,並存儲在程序集中。
例子:
1 static void Main(string[] args) 2 { 3 Expression<Func<int, bool>> expression = s => s > 1 ; 4 DisplayTree(0, "lambda", expression); 5 Console.ReadKey(); 6 } 7 static void DisplayTree(int indent, string message, Expression expression) 8 { 9 string outPut = string.Format("{0} {1} ! NodeType: {2}; Expr: {3}", "".PadLeft(indent, '>'), message, expression.NodeType, expression); 10 indent++; 11 switch (expression.NodeType) 12 { 13 case ExpressionType.Constant: 14 ConstantExpression constExpr = (ConstantExpression)expression; 15 Console.WriteLine("{0} Const Value: {1}", outPut, constExpr.Value); 16 break; 17 case ExpressionType.Equal: 18 case ExpressionType.AndAlso: 19 case ExpressionType.GreaterThan: 20 BinaryExpression binExpr = (BinaryExpression)expression; 21 if (binExpr.Method != null) 22 { 23 Console.WriteLine("{0} Method: {1}", outPut, binExpr.Method.Name); 24 } 25 else 26 { 27 Console.WriteLine(outPut); 28 } 29 DisplayTree(indent, "Left", binExpr.Left); 30 DisplayTree(indent, "Right", binExpr.Right); 31 break; 32 case ExpressionType.Lambda: 33 Console.WriteLine(outPut); 34 LambdaExpression lambdaExpr = (LambdaExpression)expression; 35 foreach (var item in lambdaExpr.Parameters) 36 { 37 DisplayTree(indent, "Parameter", item); 38 } 39 DisplayTree(indent, "Body", lambdaExpr.Body); 40 break; 41 case ExpressionType.MemberAccess: 42 MemberExpression memberExpr = (MemberExpression)expression; 43 Console.WriteLine("{0} Member Name: {1}, Type: {2}", outPut, memberExpr.Member.Name, memberExpr.Type.Name); 44 DisplayTree(indent, "Member Expr", memberExpr.Expression); 45 break; 46 case ExpressionType.Parameter: 47 ParameterExpression parameExpr = (ParameterExpression)expression; 48 Console.WriteLine("{0} Param Type: {1}", outPut, parameExpr.Type.Name); 49 break; 50 default: 51 Console.WriteLine(); 52 Console.WriteLine("{0} {1}", expression.NodeType, expression.Type.Name); 53 break; 54 } 55 }