對象初始化器
到目前, 我們所有的select語句都返回了包含單一元素的類型. 使用C#的對象初始化器, 我們可以構造更加復雜的類型. 例如, 我們想構造一個查詢, 用來去除一個名字列表中的所有元素中包含的元音字符, 並且最後仍然要包含原始值. 我們可以構造以下的類型來協助:
1: class TempProjectionItem
2: {
3: public string Original;
4: public string Vowelless;
5: }
然後我們使用對象初始化器來將值注入:
1: IEnumerable<TempProjectionItem> temp =
2: from n in names
3: select new TempProjectionItem
4: {
5: Original = n,
6: Vowelless = n.Replace ("a", "").Replace ("e", "").
7: Replace ("i", "").Replace ("o", "").Replace ("u", "")
8: };
其返回類型是IEnumerable<TempProjectionItem>, 我們可以使用它來做進一步的子查詢:
1: IEnumerable<string> query = from item in temp
2: where item.Vowelless.Length > 2
3: select item.Original;
匿名類型
匿名類型允許你構造在沒有編寫特殊類型的情況下構造中間結果值. 例如在上面的例子中, 我們如果使用匿名類型的話則完全可以去掉TempProjectionItem類:
1: var intermediate = from n in names
2: select new
3: {
4: Original = n,
5: Vowelless = Regex.Replace (n,"[aeiou]", "")
6: };
7:
8: IEnumerable<string> query1 =
9: from item in intermediate
10: where item.Vowelless.Length > 2
11: select item.Original;
這個查詢會得到和上面一樣的結果, 但是卻不必要編寫那個只使用一次的數據類, 編譯器會在後端創建一個臨時類, 此臨時類會根據查詢產生的投影值的數據類型產生對應的字段. 這意味著, 這個intermediate的查詢擁有一個這樣的類型:
IEnumerable<random-compiler-produced-name>, 要聲明一個這樣的類似, 唯一的辦法只有使用var關鍵字.
使用into的話我們還可以讓整個查詢更加簡潔:
1: var query = from n in names
2: select new
3: {
4: Original = n,
5: Vowelless = Regex.Replace (n,"[aeiou]", "")
6: }
7: into temp
8: where temp.Vowelless.Length > 2
9: select temp.Original;
let關鍵字
let關鍵字是一個緊靠枚舉變量的新的變量. 使用let, 我們像下面這樣編寫一個查詢來解析那些去掉元音字符之後長度依然大於2的字符串:
1: string[] names = {"Tom","Dick","Harry","Mary","Jay" };
2: IEnumerable<string> query =
3: from n in names
4: let vowelless = Regex.Replace (n,"[aeiou]", "")
5: where vowelless.Length > 2
6: orderby vowelless
7: select n; //因為使用了let, n依然還在可用范圍內
編譯器將let子句翻譯成一個臨時的匿名類型, 此匿名類型包含了迭代變量和新的表達式變量. 換句話說, 編譯器將這個查詢轉換成我們之前提到的例子. 待續!