ToList with Capacity?

时间:2017-11-09 17:48:20

标签: c#

当我们为.ToList()执行IEnumerable时,列表可能会在扫描IEnumerable时重新分配,因为它不知道预先确定的大小。如果已知大小,是否有一种简单的方法可以避免性能损失?初始化具有所需容量的List然后将IEnumerable复制到其中的效果?理想情况下就像.ToList(capacity)一样简单(不存在)。

1 个答案:

答案 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;
    }
}