当我们为.ToList()
执行IEnumerable
时,列表可能会在扫描IEnumerable
时重新分配,因为它不知道预先确定的大小。如果已知大小,是否有一种简单的方法可以避免性能损失?初始化具有所需容量的List
然后将IEnumerable
复制到其中的效果?理想情况下就像.ToList(capacity)
一样简单(不存在)。
答案 0 :(得分:3)
如果容量是IEnumerable<T>
的一部分且也是ICollection<T>
,则库将以正确的容量进行分配。
以下是reference implementation of List<T>(IEnumerable<T> source)
,在您致电ToList()
时调用:
public List(IEnumerable<T> collection) {
if (collection==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
Contract.EndContractBlock();
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
if (count == 0) {
_items = _emptyArray;
} else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
} else {
_size = 0;
_items = _emptyArray;
// This enumerable could be empty. Let Add allocate a new array, if needed.
// Note it will also go to _defaultCapacity first, not 1, then 2, etc.
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Add(en.Current);
}
}
}
}
注意构造函数在collection
实现ICollection<T>
时的行为:不是迭代内容并为每个项调用Add
,而是分配内部_items
数组,并复制没有重新分配的内容。
在实现IEnumerable<T>
的类中不的容量中,您可以使用标准方法的组合轻松定义一个:
static class ToListExtension {
public static List<T> ToList(this IEnumerable<T> source, int capacity) {
var res = new List<T>(capacity);
res.AddRange(source);
return res;
}
}