这是一个两遍算法吗?即,它迭代枚举一次以计算元素的数量,以便它可以分配数组,然后再次传递插入它们?
它是否循环一次,并继续调整阵列的大小?
或者它是否使用像List这样的中间结构(可能在内部调整数组大小)?
dri*_*iis 17
它使用中间结构.涉及的实际类型是Buffer,它是框架中的内部结构.实际上,这种类型有一个数组,每次完整时都会复制它以分配更多空间.这个数组的长度为4(在.NET 4中,它是一个可能会改变的实现细节),因此在执行ToArray时可能最终会分配和复制很多.
不过,有一个优化的地方.如果源实现ICollection<T>,它使用Count from the从头开始分配正确的数组大小.
Gab*_*abe 10
首先,它检查源是否是一个ICollection<T>,在这种情况下,它可以调用源的ToArray()方法.
否则,它只列举一次源.因为它枚举它将项目存储到缓冲区数组中.每当它到达缓冲区数组的末尾时,它就会创建一个大小为两倍的新缓冲区并复制旧元素.枚举完成后,它返回缓冲区(如果它的大小正确)或将项目从缓冲区复制到一个完全正确大小的数组中.
这是操作的伪源代码:
public static T[] ToArray<T>(this IEnumerable<T> source)
{
T[] items = null;
int count = 0;
foreach (T item in source)
{
if (items == null)
{
items = new T[4];
}
else if (items.Length == count)
{
T[] destinationArray = new T[count * 2];
Array.Copy(items, 0, destinationArray, 0, count);
items = destinationArray;
}
items[count] = item;
count++;
}
if (items.Length == count)
{
return items;
}
T[] destinationArray = new TElement[count];
Array.Copy(items, 0, destinationArray, 0, count);
return destinationArray;
}
Run Code Online (Sandbox Code Playgroud)
像这样(通过.NET Reflector):
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
Buffer<TSource> buffer = new Buffer<TSource>(source);
return buffer.ToArray();
}
[StructLayout(LayoutKind.Sequential)]
internal struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int length = 0;
ICollection<TElement> is2 = source as ICollection<TElement>;
if (is2 != null)
{
length = is2.Count;
if (length > 0)
{
array = new TElement[length];
is2.CopyTo(array, 0);
}
}
else
{
foreach (TElement local in source)
{
if (array == null)
{
array = new TElement[4];
}
else if (array.Length == length)
{
TElement[] destinationArray = new TElement[length * 2];
Array.Copy(array, 0, destinationArray, 0, length);
array = destinationArray;
}
array[length] = local;
length++;
}
}
this.items = array;
this.count = length;
}
internal TElement[] ToArray()
{
if (this.count == 0)
{
return new TElement[0];
}
if (this.items.Length == this.count)
{
return this.items;
}
TElement[] destinationArray = new TElement[this.count];
Array.Copy(this.items, 0, destinationArray, 0, this.count);
return destinationArray;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6187 次 |
| 最近记录: |