Die*_*ego 12 .net linq .net-4.0
几年前,有人抱怨实施,Linq.Reverse()微软承诺解决这个问题.这是在2008年,所以问题是,框架4是否有一个优化的实现,Linq.Reverse()当集合类型允许时(例如IList<T>),没有实现集合(即将所有元素复制到内部数组)?
svi*_*ick 13
显然,不可能优化所有案例.如果某个对象仅实现IEnumerable<T>而不实现IList<T>,则必须迭代它直到结束才能找到最后一个元素.因此优化仅适用于实现的类型IList<T>(如T[]或List<T>).
现在,是它实际上在.NET 4.5 DP优化?让我们启动Reflector ILSpy:
public static IEnumerable<TSource> Reverse<TSource>(
this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return ReverseIterator<TSource>(source);
}
Run Code Online (Sandbox Code Playgroud)
好的,ReverseIterator<TSource>()看起来怎么样?
private static IEnumerable<TSource> ReverseIterator<TSource>(
IEnumerable<TSource> source)
{
Buffer<TSource> buffer = new Buffer<TSource>(source);
for (int i = buffer.count - 1; i >= 0; i--)
{
yield return buffer.items[i];
}
yield break;
}
Run Code Online (Sandbox Code Playgroud)
迭代器块的作用是Buffer<T>为集合创建一个并向后迭代.我们快到了,有什么Buffer<T>?
[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;
}
// one more member omitted
}
Run Code Online (Sandbox Code Playgroud)
我们在这里有什么?我们将内容复制到数组中.在每种情况下.唯一的优化是,如果我们知道Count(即集合实现ICollection<T>),我们就不必重新分配数组.
因此,对于优化IList<T>是不是在.NET 4.5 DP.它会在每种情况下创建整个集合的副本.
如果我猜测为什么它没有被优化,在阅读Jon Skeet关于这个问题的文章之后,我认为这是因为优化是可观察的.如果在迭代时改变集合,您将看到更改后的数据与优化,但没有它的旧数据.实际上以微妙的方式改变某些行为的优化是一件坏事,因为它具有向后兼容性.