为什么列表中的额外复制 .AddRange(IEnumerable的 )?

问题描述 投票:12回答:1

我正在查看System.Collections.Generic.List<T>的开源代码。 AddRange(IEnumerable<T>)方法如下所示:

public void AddRange(IEnumerable<T> collection) {
     Contract.Ensures(Count >= Contract.OldValue(Count));

     InsertRange(_size, collection);
}

InsertRange(int, IEnumerable<T>)方法看起来像这样:

public void InsertRange(int index, IEnumerable<T> collection) {
    if (collection==null) {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
    }

    if ((uint)index > (uint)_size) {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
    }
    Contract.EndContractBlock();

    ICollection<T> c = collection as ICollection<T>;
    if( c != null ) {
        int count = c.Count;
        if (count > 0) {
            EnsureCapacity(_size + count);
            if (index < _size) {
                Array.Copy(_items, index, _items, index + count, _size - index);
            }

            if (this == c) {
                Array.Copy(_items, 0, _items, index, index);
                Array.Copy(_items, index+count, _items, index*2, _size-index);
            }
            else {
                T[] itemsToInsert = new T[count];        // WHY?
                c.CopyTo(itemsToInsert, 0);              // WHY?
                itemsToInsert.CopyTo(_items, index);     // WHY?

                // c.CopyTo(_items, index);              // WHY NOT THIS INSTEAD???
            }
            _size += count;
        }             
    }
    else {
        using(IEnumerator<T> en = collection.GetEnumerator()) {
            while(en.MoveNext()) {
                Insert(index++, en.Current);                                    
            }                
        }
    }
    _version++;            
}

假设我们这样打电话:

var list1 = new List<int> {0, 1, 2, 3};
var list2 = new List<int> {4, 5, 6, 7};
list1.AddRange(list2);

当这在内部击中InsertRange(int, IEnumerable<T>)时,它最终会击中// WHY?评论突出显示的其他条件。

为什么分配了一个数组,将list2中的元素复制到该临时数组中,然后将这些元素从该临时数组复制到list1的末尾?为什么额外的副本?为什么不直接使用list2方法将元素从list1复制到ICollection<T>.CopyTo()的末尾?


EDIT

我会恭敬地提出,虽然这个问题受到我们这些没有编写代码的人的推测,但仍然有一个问题的答案。代码的编写方式是有原因的,我希望有知识的人可以提供解释,即使只是出于历史目的。

c# .net performance generics generic-list
1个回答
1
投票

正如@ OlivierJacot-Descombes的评论部分所述,有关的额外副本已在.NET核库(CoreFX)的当前版本的List.cs中删除,并被单拷贝版本(即c.CopyTo(_items, index);)取代。

感谢@elgonzo和@IvanStoev提供发人深省的评论。总而言之,这可能只是List<T>演变的一个人工制品,并且代表了它开发时的最佳选择,但这只是猜测。

© www.soinside.com 2019 - 2024. All rights reserved.