var fillData = new List<int>();
for (var i = 0; i < 100000; i++)
{
fillData.Add(i);
}
var stopwatch1 = new Stopwatch();
stopwatch1.Start();
var autoFill = new List<int>();
autoFill.AddRange(fillData);
stopwatch1.Stop();
var stopwatch2 = new Stopwatch();
stopwatch2.Start();
var manualFill = new List<int>();
foreach (var i in fillData)
{
manualFill.Add(i);
}
stopwatch2.Stop();
Run Code Online (Sandbox Code Playgroud)
当我把4个结果从stopwach1和stopwach2,stopwatch1具有比始终较低值stopwatch2.这意味着addrange总是快于foreach.有谁知道为什么?
Jon*_*eet 85
潜在地,AddRange可以检查传递给它的值实现的位置IList或IList<T>.如果是,它可以找出该范围内有多少个值,因此需要分配多少空间......而foreach循环可能需要重新分配几次.
此外,即使在分配之后,List<T>也可以使用IList<T>.CopyTo执行批量复制到底层数组(IList<T>当然,对于实现的范围).
我怀疑你会发现,如果你再次使用,但您尝试测试Enumerable.Range(0, 100000)的fillData,而不是一个List<T>,两个将采取大约在同一时间.
Mar*_*ell 58
如果您正在使用Add,则会根据需要(加倍)逐步调整内部数组的大小,从默认的起始大小10(IIRC)开始.如果您使用:
var manualFill = new List<int>(fillData.Count);
Run Code Online (Sandbox Code Playgroud)
我希望它会彻底改变(不再调整大小/数据副本).
从反射器,AddRange内部,而不是增长倍增:
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
if (count > 0)
{
this.EnsureCapacity(this._size + count);
// ^^^ this the key bit, and prevents slow growth when possible ^^^
Run Code Online (Sandbox Code Playgroud)
List AddRange方法的反射器反汇编具有以下代码
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
if (count > 0)
{
this.EnsureCapacity(this._size + count);
if (index < this._size)
{
Array.Copy(this._items, index, this._items, index + count, this._size - index);
}
if (this == is2)
{
Array.Copy(this._items, 0, this._items, index, index);
Array.Copy(this._items, (int) (index + count), this._items, (int) (index * 2), (int) (this._size - index));
}
else
{
T[] array = new T[count];
is2.CopyTo(array, 0);
array.CopyTo(this._items, index);
}
this._size += count;
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,有一些优化,如EnsureCapacity()调用和使用Array.Copy().
使用AddRangeCollection时,可以增加一次数组的大小,然后将值复制到其中.
使用foreach语句,集合需要多次增加集合的大小.
增加thr大小意味着复制需要时间的完整数组.