21.5.7 查詢中的匿名型別
21.5.8 group 子句
21.5.9 查詢延續
21.6 標準查詢運算子
21.6.3 委託作為參數
21.6.4 LINQ預定義的委託類型
21.6.5 使用委託參數的樣本
21.6.6 使用 Lambda 運算式參數的樣本
21.5.7 查詢中的匿名型別
select new { s.LastName, s.FirstName, s.Major };
21.5.8 group 子句
group子句把select的對象根據一些標準分組。
group student by student.Major ;
如果項目包含在查詢的結果中,它們就可以根據某個欄位的值進行分組。作為分組一句的項叫做鍵(Key)。
static void Main() { var students = new[] // Array of objects of an anonymous type { new { LName="Jones", FName="Mary", Age=19, Major="History" }, new { LName="Smith", FName="Bob", Age=20, Major="CompSci" }, new { LName="Fleming", FName="Carol", Age=21, Major="History" } }; var query = from student in students group student by student.Major; foreach (var s in query) // Enumerate the groups. { Console.WriteLine("{0}", s.Key); foreach (var t in s) // Enumerate the items in the group. Console.WriteLine(" {0}, {1}", t.LName, t.FName); } }
21.5.9 查詢延續
查詢延續子句可以接受查詢的一部分結果並賦予一個名字,從而可以在查詢的另一部分中使用。查詢延續的文法如下。
樣本:
查詢串連了groupA和groupB,並且命名為groupAandB,然後從groupA和groupB中進行一個簡單的select。
static void Main() { var groupA = new[] { 3, 4, 5, 6 }; var groupB = new[] { 4, 5, 6, 7 }; var someInts = from a in groupA join b in groupB on a equals b into groupAandB //查詢繼續 from c in groupAandB select c; foreach (var a in someInts) Console.Write("{0} ", a); }
21.6 標準查詢運算子
標準查詢運算子由一系列的API的方法組成,它能讓我們查詢任何.NET數組和集合。
1.被查詢的集合對象叫序列,它必須實現 IEnumerable<T> 介面,T是類型。
2.標準查詢運算子使用方法文法。
3.一些運算子返回IEnumerable對象(或其他序列),而其他的一些運算子返回標量。返回標量的運算子立即執行,而返回替代可枚舉類型對象的值會被延遲迭代。
class Program { static int[] numbers = new int[] { 2, 4, 6 }; static void Main() { int total = numbers.Sum(); int howMany = numbers.Count(); // ↑ ↑ ↑ //標量對象 序列 運算子 Console.WriteLine("Total: {0}, Count: {1}", total, howMany); } }
21.6.3 委託作為參數
查詢運算式Count的定義:
每一個運算子的第一個參數是IEnumerable<T>對象的引用,之後是參數可以是任何類型。很多運算子接受泛型委派作為參數。泛型委派用於給使用者提供自訂的代碼。
為瞭解釋,首先從示範 Count 運算子的幾種使用方法開始。Count 運算子被重載並且有兩種形式。第一種,
public static int Count<TSource>(this IEnumerable<TSource> source);
和所有擴充方法差不多,我們可以使用標準靜態方法形式或在一個擴充類上使用執行個體方法的形式,如下:
var count1 = System.Linq.Enumerable.Count(intArry); // 靜態方法形式
var count2 = intArry.Count(); // 執行個體方法形式
查詢統計給定的整數數組中int的總數。然而,我們希望看看數組中奇數元素的總數,我們必須指定 Count 方法的第二種形式才能實現,如下所示。它有一個泛型委派作為其第二個參數。調用時,我們必須提供一個接受單個 TSource 類型的輸入參數並返回布爾值的委派物件。委託代碼的傳回值必須指定元素是否包含在總數中。
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
例如,通過一個lambda運算式在輸入值是奇數時返回true,否則返回false。如果是奇數,Count會把這個元素包含在總數中。
static void Main() { int[] intArray = new int[] { 3, 4, 5, 6, 7, 9 }; var countOdd = intArray.Count(n => n % 2 == 1); Console.WriteLine("Count of odd numbers: {0}", countOdd); }
3,5,7,9是奇數
Count of odd numbers: 4
請按任意鍵繼續. . .
21.6.4 LINQ預定義的委託類型
LINQ定義了兩套泛型委派類型與標準查詢運算子一起使用。它們就是 Func 委託及 Action 委託,各有17個成員。
(翻譯Func:函數、功能)
1.TR帶表了傳回值,並且總是在型別參數列表的最後一個。
2.注意傳回型別參數有一個out,使之可以協變,也就是說可以接受聲明的類型或從這個類型派生的類型。
3.輸入參數有一個in,使之可以逆變,也就是你可以接受聲明的類型或從這個類型派生的類型。
我們再來看看Count的聲明。發現第二個參數必須是委派物件,它接受單個T類型的參數作為方法參數並返回一個bool類型值。
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); // ↑ ↑ // 參數類型 傳回型別
產生一個布爾值的參數委託叫做謂詞。
下面是4個Action委託。只是沒有傳回值,和Func委託相似。所有參數類型都是逆變。
21.6.5 使用委託參數的樣本
如下面代碼我們先聲明IsOdd方法,它接受單個int類型的參數,並且返回表示輸入參數是否為奇數的bool值。Main方法做了如下事情。
1.聲明了int數組作為資料來源。
2.它建立了一個類型為Func<int,bool>名稱為MyDel的委派物件,並且使用IsOdd方法來初始化委派物件。注意,我們不需要聲明Func委託類型,因為LINQ已經預定義了。
3.它使用委派物件調用Count。
static bool IsOdd(int x) // Method to be used by the delegate object { return x % 2 == 1; // Return true if x is odd. } static void Main() { int[] intArray = new int[] { 3, 4, 5, 6, 7, 9 }; Func<int, bool> myDel = new Func<int, bool>(IsOdd); // Delegate object var countOdd = intArray.Count(myDel); // Use delegate Console.WriteLine("Count of odd numbers: {0}", countOdd); }
21.6.6 使用 Lambda 運算式參數的樣本
如果方法在其他地方被調用,而不僅僅是用來初始化委派物件,前面的方法很好,然而,如果希望更簡潔和更局部化的方法,就使用Lambda運算子。
static void Main() { int[] intArray = new int[] { 3, 4, 5, 6, 7, 9 }; var countOdd = intArray.Count(x => x % 2 == 1); Console.WriteLine("Count of odd numbers: {0}", countOdd); }