標籤:
對於聲明為:public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);而言,調用它的形式就是: AList.SelectMany(itm=>itm.listProp); // 其中AList中的屬性裡有 也是集合的 屬性listProp。listProp集合元素類型是TResult。
對於 AList.Select(itm=>itm.listProp)返回的是 IEnumerable<List<TResult>>
現在對於聲明為:public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
// TResult 中的欄位 可以由 TSource和TCollection一起構成,當然也可以只 由TCollection的某些欄位單獨構成。
// 可以 假設:Class中有GradeId和ClassId欄位和 List<Student> studs,而Student只有ClassId沒有GradeId;那麼
// IEnumerable<TSource>就是 Class的集合。 而 IEnumerable<TCollection>就是 Class中 Student的集合。
// 這時候調用 SelectMany的形式就是 classes.SelectMany(class=>class.studs,(class,stud)=>new{GradeId=class.GradeId,StudentId=stud.StudentId,...});
// 其中 classes就是 source, stud則是 studs中的元素。且如果方法中出現了兩個委託參數,一般而言第二個委託需要間接用到第一個委託的傳回值。
// 這個例子就說明了,為什麼第二個委託裡需要傳 class。
1 // 調用的時候是 source.SelectMany(i=>i.listProp,(i,s)=>...); i就是下面的itm
// TSource就類似Class;TCollection就類似 Student; TResult則是 第二個委託的傳回值的 類型,可以是匿名型別 2 public IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(source,collectionSelector,resultSelector) 3 { 4 IEnumerable<TResult> listResult = new IEnumerable<TResult>();
// source就類似上面的 classes 5 foreach(var itm in source) 6 { 7 // collectionSelector(itm)返回的是 itm.listProp; 8 // itm.listProp的類型 就是 TCollection 類型。 9 IEnumerable<TCollection> blockCollection = collectionSelector(itm); // blockCollection類似某class 的studs10 // 如果沒有後面的 resultSelector那麼這時候實際上會執行 listResult.AddRange(blockList);11 12 // IEnumerable<TResult> blockResult=new List<TResult>13 foreach(var citm in blockCollection)// 類似上面的studs14 {15 // 這裡之所以用到 itm 是因為 TResult 中的欄位未必都是 citm 裡進行了刪減,而還包括一些擴增,擴增的16 // 欄位就可以是 itm中的。 舉個栗子: itm是 Trade(有多個Order,即是 blockCollection),而 citm則是 Order,17 // 那麼這時候返回的 Result未必 是 Order的屬性縮減後得到的新的 對象,還可以是 itm中除了 blockCollection屬性外的18 // 其它屬性,例如收貨人姓名 和 Order中的屬性進行拼接。(注意,Order之前是沒有收貨人姓名的,因為一個 Order必然是19 // 屬於一個具體的 Trade,而一個Trade是由一個 買家購買物品產生的,故只需要在 Trade中有收件者姓名即可。這裡我們20 // 將收件者姓名這個屬性 整合到了 Order中形成 ‘Order ,即 TResult。21 // 所以說,之前覺得 itm是沒必要的是因為自己沒有搞懂 這個SelectMany的功能。總以為 對一個結構進行修改形成新的22 // 結構只是說 對原來的結構進行 修剪, 現在才知道,實際上還可以 對原來的結構進行 增加,而用什麼增加,既可以是23 // 無關的資料,也可以是該結構的上級的資料。24 listResult.Add(resultSelection(itm, citm)); // resultSelection(itm,citm)的傳回值就是 TResult 對象25 }26 }27 return listResult;28 }
C#Linq技術中SelectMany(...)的內部實現推測