难道System.Linq.Enumerable.Reverse内部复制所有元素的数组? [英] Does System.Linq.Enumerable.Reverse copy all elements internally to an array?

查看:141
本文介绍了难道System.Linq.Enumerable.Reverse内部复制所有元素的数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几年前,<一个href="http://connect.microsoft.com/VisualStudio/feedback/details/355096/system-linq-enumerable-reverse-does-not-provide-optimized-implementation-when-its-argument-is-an-ilist-t"相对=nofollow>有人抱怨 Linq.Reverse()和微软承诺修复的实施。这是在2008年,这样的问题是,框架4有一个优化的实施 Linq.Reverse()不兑现的集合(即​​所有元素复制到内部数组),当集合类型支持的话(例如:的IList&LT; T&GT;

Some years back, somebody complained about the implementation of Linq.Reverse() and Microsoft promised to fix that. This was in 2008, so the question is, does Framework 4 have an optimized implementation of Linq.Reverse() that does not materialize the collection (i.e. copy all elements to an internal array) when the collection type allows it (e.g. IList<T>)?

推荐答案

显然这是不可能的,以优化所有情况。如果某些对象实现仅的IEnumerable&LT; T&GT; ,而不是的IList&LT; T&GT; ,你必须重复它,直到结束找到的最后一个元素。所以,优化将只适用于实现类型的IList&LT; T&GT; (如 T [] 列表&LT; T&GT;

Obviously it's not possible to optimize all cases. If some object implements only IEnumerable<T> and not IList<T>, you have to iterate it until the end to find the last element. So the optimization would be only for types that implement IList<T> (like T[] or List<T>).

现在,的实际优化的.Net 4.5 DP?让我们火了反射 ILSpy:

Now, is it actually optimized in .Net 4.5 DP? Let's fire up Reflector ILSpy:

public static IEnumerable<TSource> Reverse<TSource>(
    this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return ReverseIterator<TSource>(source);
}

好了,请问 ReverseIterator&LT; TSource&GT;()

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

什么是迭代器块确实是创建一个缓存器; T&GT; 的收集,并通过遍历倒退。我们快到了,有什么缓存器; T&GT;

What that iterator block does is to create a Buffer<T> for the collection and iterate backwards through that. We're almost there, what's 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
}

我们还有什么吗?我们的内容复制到一个数组。在任何情况下。唯一的优化是,如果我们知道计数(即,收集工具的ICollection&LT; T&GT; ),我们不'T不得不重新分配阵列。

What have we here? We copy the content to an array. In every case. The only optimization is that if we know Count (that is, the collection implements ICollection<T>), we don't have to reallocate the array.

因此​​,优化的IList&LT; T&GT; 不可以在.net 4.5 DP。它在任何情况下创建整个集合的副本。

So, the optimization for IList<T> is not in .Net 4.5 DP. It creates a copy of the whole collection in every case.

如果我要猜测为什么它不是最优化的,看完后<一href="http://msmvps.com/blogs/jon_skeet/archive/2011/01/08/reimplementing-linq-to-objects-part-27-reverse.aspx">Jon飞碟双向在这个问题上的文章,我认为这是因为优化是可观察的。如果发生变异的集合,而迭代,你会看到改变的数据与优化,但旧的数据没有它。和优化,实际上改变了什么行为,以微妙的方式是因为向后兼容性是一件坏事。

If I were to guess why it isn't optimized, after reading Jon Skeet's article on this issue, I think it's because that optimization is observable. If you mutate the collection while iterating, you would see the changed data with the optimization, but the old data without it. And optimizations that actually change behavior of something in subtle ways are a bad thing, because of backwards compatibility.

这篇关于难道System.Linq.Enumerable.Reverse内部复制所有元素的数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆