Linq做了很多聪明的事情,比如在Count
上使用IList
()方法返回Count属性的结果。
是否有一个很好的来源概述了这种优化?
这将是非常有趣的,因为像以前我知道上述情况一样,我从未使用Count()
因此经常返回List<T>
而不是IEnumerable<T>
,因为我知道调用者需要通常需要列表的实例计数。
但是请记住,Count()并不真正计算IEnumerable<T>
中包含的实例,而是从返回的List返回Count属性的结果,因此不会失去性能,这让我改变了很多我将列表中的返回类型转换为IEnumerable<T>
。
答案 0 :(得分:13)
试试.NET Reflector。它是浏览类库的一个很好的工具,它有一个强大的反编译器,让你可以像编写它一样查看源代码。
e.g。 Count()
扩展方法就像这样实现
if (source == null)
{
throw Error.ArgumentNull("source");
}
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
return is2.Count;
}
ICollection is3 = source as ICollection;
if (is3 != null)
{
return is3.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num++;
}
}
return num;
如果源没有实现集合接口,您将不得不计算得到实际的帐户。以这种方式浏览代码是一种很好的学习方式。
答案 1 :(得分:6)
我所知道的当前优化:
Count
并且未使用谓词,则 Count
使用ICollection<T>
属性。 (在.NET 4中,Count
也针对非通用ICollection
进行了优化。)
ElementAt
,则 ElementAtOrDefault
/ IList<T>
按索引访问。
IList<T>
并且未使用谓词,则 Last
/ LastOrDefault
按索引访问。
ToArray
/ ToList
如果序列实现Count
,则使用ICollection<T>
属性更有效地分配内存。 (但它们都没有针对ICollection
进行优化。)
可能存在的优化但不是:
Last
/ LastOrDefault
在使用谓词的情况下不进行优化。他们没有理由不能优化IList<T>
,在列表中向后迭代并按索引访问每个元素。
SequenceEqual
可以针对ICollection<T>
和ICollection
进行优化,使用Count
属性来确定列表是否具有相同的长度并且如果它们是早期就爆发不要。
Skip
可以针对IList<T>
进行优化,通过索引访问元素并直接从索引 n 开始,而不是迭代并丢弃第一个 n < / em> elements。
ToArray
/ ToList
也可以优化ICollection
,使用Count
属性更有效地分配内存。
ToDictionary
可针对ICollection<T>
和ICollection
进行优化,使用Count
属性更有效地分配内存。