Lista <T> .AddRange suboptimal de implementación

El perfil de mi aplicación de C # indicó que se ha invertido un tiempo significativo enList<T>.AddRange. El uso de Reflector para ver el código en este método indica que llamaList<T>.InsertRange&nbsp;que se implementa como tal:

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;

Se puede argumentar que la simplicidad de la interfaz (que solo tiene una sobrecarga de InsertRange) justifica la sobrecarga de rendimiento de cheching y casting de tipo runtime. Pero, ¿cuál podría ser la razón detrás de las 3 líneas que he indicado con(*)&nbsp;? Creo que podría reescribirse a la alternativa más rápida:

is2.CopyTo(this._items, index);

¿Ves alguna razón para no usar esta alternativa más simple y aparentemente más rápida?

Editar:

Gracias por las respuestas. Por lo tanto, la opinión general es que esta es una medida de protección contra la recopilación de entrada que implementa CopyTo de manera defectuosa / maliciosa. A mí me parece una exageración pagar constantemente el precio de 1) verificación del tipo de tiempo de ejecución 2) asignación dinámica de la matriz temporal 3) duplicar la operación de copia, cuando todo esto podría haberse guardado definiendo 2 o unas cuantas sobrecargas más de InsertRange , uno consiguiendoIEnumerable&nbsp;como ahora, el segundo consigue unList<T>tercero obteniendoT[]. Los dos últimos podrían haber sido implementados para correr alrededor del doble de rápido que en el caso actual.

Edición 2:

Implementé una clase FastList, idéntica a la Lista, excepto que también proporciona una sobrecarga de AddRange que toma un argumento T []. Esta sobrecarga no necesita la verificación de tipo dinámico y la copia doble de elementos. Hice un perfil de este FastList.AddRange contra List.AddRange agregando matrices de 4 bytes 1000 veces a una lista que inicialmente estaba vacía. Mi implementación supera la velocidad de List.AddRange estándar con un factor de 9 (¡nueve!). List.AddRange toma aproximadamente el 5% del tiempo de ejecución en uno de los escenarios de uso importantes de nuestra aplicación, reemplazando a List con una clase que proporciona un AddRange más rápido podría mejorar el tiempo de ejecución de la aplicación en un 4%.