咨询区
Shlomo:
.ToLookup<TSource, TKey>
返回的是 ILookup<TKey, TSource>
, 但我发现 ILookup<TKey, TSource>
同时也实现了 IEnumerable<IGrouping<TKey, TSource>>
接口。
.GroupBy<TSource, TKey>
直接返回的是 IEnumerable<IGrouping<Tkey, TSource>>
接口。
ILookup 有一个方便的属性索引器,所以它具有像字典一样的行为,但 GroupBy 却不能,所以用起来很痛苦,唯一的方式就是通过 foreach 对其进行迭代,换句话说,GroupBy 能做的,貌似 ToLookup 都能很好的完成。
总之,给我的疑惑就是,有了 ToLookup()
是不是 GroupBy()
就没用武之地了?
回答区
Allon Guralnek:
这两者是类似的,但它们的应用场景完全不一样, .ToLookup()
方法返回的是所有已经分好组的可立即使用的对象,简而言之就是 立即加载
, 可参考其源码:
public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{return Lookup<TKey, TSource>.Create(source, keySelector, IdentityFunction<TSource>.Instance, null);
}internal static Lookup<TKey, TElement> Create<TSource>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
{if (source == null){throw Error.ArgumentNull("source");}if (keySelector == null){throw Error.ArgumentNull("keySelector");}if (elementSelector == null){throw Error.ArgumentNull("elementSelector");}Lookup<TKey, TElement> lookup = new Lookup<TKey, TElement>(comparer);foreach (TSource item in source){lookup.GetGrouping(keySelector(item), create: true).Add(elementSelector(item));}return lookup;
}
可以看到,它里面已经执行了 foreach 操作。
.GroupBy()
它仅仅是构建了一个可迭代类,所以它是一个懒加载操作,参考如下源码:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{return new GroupedEnumerable<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, null);
}public GroupedEnumerable(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
{if (source == null){throw Error.ArgumentNull("source");}if (keySelector == null){throw Error.ArgumentNull("keySelector");}if (elementSelector == null){throw Error.ArgumentNull("elementSelector");}this.source = source;this.keySelector = keySelector;this.elementSelector = elementSelector;this.comparer = comparer;
}
针对数据库的 Linq To Database 来说, GroupBy()
会被解析成 sql 中的 group by
关键词,所以它会在server端被执行而不是在客户端,因此如果你想在 group key 上做一些过滤条件,比如: (having),这是完全支持的,相关 Tolookup()
是将所有的数据加载到 client 内存中,然后在内存中做 groupby 操作,所以刚才说的附加过滤操作是无法支持的。
点评区
其实说的再多,一看源码就什么都知道了,所以说 ILSpy,Reflector,Dnspy 随身备着哈。