首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >List<T>.AddRange实现次优

List<T>.AddRange实现次优
EN

Stack Overflow用户
提问于 2010-01-23 12:44:24
回答 2查看 10.2K关注 0票数 21

分析我的C#应用程序表明,在List<T>.AddRange上花费了大量的时间。使用Reflector查看此方法中的代码表明它调用了List<T>.InsertRange,其实现方式如下:

代码语言:javascript
复制
public void InsertRange(int index, IEnumerable<T> collection)
{
    if (collection == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
    }
    if (index > this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
    }
    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;
        }
    }
    else
    {
        using (IEnumerator<T> enumerator = collection.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                this.Insert(index++, enumerator.Current);
            }
        }
    }
    this._version++;
}

private T[] _items;

可以说,接口的简单性(只有一个过载的InsertRange)证明运行时类型检查和转换的性能开销是合理的。但是,我用(*)指出的这三行背后的原因是什么呢?我认为它可以改写成更快的替代方案:

代码语言:javascript
复制
is2.CopyTo(this._items, index);

你认为没有理由不使用这一简单和明显更快的替代方案吗?

编辑:

谢谢你的回答。因此,大家一致认为,这是一种针对以缺陷/恶意方式实现CopyTo的输入集合的保护措施。在我看来,经常支付1)运行时类型检查( 2)临时数组的动态分配(动态分配)是复制操作的两倍的代价似乎是一种过度,当所有这些都可以通过定义2或几个InsertRange重载来保存的时候,一个是现在的IEnumerable,第二个是List<T>,第三个是T[]。后两者可以实现,运行速度大约是当前情况的两倍。

编辑2:

我确实实现了一个类FastList,与List完全相同,只不过它还提供了一个AddRange重载,其中包含一个T[]参数。此重载不需要动态类型验证和元素的双重复制。我通过向最初是emtpy的列表中添加了1000次4字节数组来分析这个FastList.AddRange与List.AddRange之间的关系。我的实现以9(9!)的倍数超过了标准List.AddRange的速度。在我们的应用程序的一个重要使用场景中,List.AddRange占用了大约5%的运行时,用提供更快AddRange的类替换List可以使应用程序运行时提高4%。

EN

回答 2

Stack Overflow用户

发布于 2010-01-23 13:39:28

这是个好问题,我正努力想出一个理由。参考源中没有提示。一种可能是,当实现ICollection<>.CopyTo()方法的类反对复制到0以外的开始索引时,它们试图避免出现问题。或者作为一种安全措施,防止集合干扰它不应该访问的数组元素。

另一种情况是,当集合以线程不安全的方式使用时,这是一种对策。如果一个项是由另一个线程添加到集合中的,那么失败的将是集合类的CopyTo()方法,而不是微软代码。合适的人会接到服务电话。

这些都不是很好的解释。

票数 2
EN

Stack Overflow用户

发布于 2010-01-23 14:49:38

如果您考虑一下解决方案,如果您以这种方式更改代码,那么您的解决方案就会出现问题,您实际上是在赋予应该添加到内部数据结构的访问权限的集合。

这不是一个好主意,例如,如果列表数据结构的作者想出了比数组更好的底层结构来存储数据,那么就无法更改List的实现,因为所有集合都期望将一个数组放入CopyTo函数。

本质上,您将巩固List类的实现,尽管面向对象编程告诉我们,数据结构的内部实现应该是可以更改的,而不会破坏其他代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2123161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档