¿Por qué IList no es compatible con AddRange?

89

List.AddRange()existe, pero IList.AddRange()no lo hace.
Esto me parece extraño. ¿Cuál es la razón detrás de esto?

Boris Callens
fuente

Respuestas:

68

Porque una interfaz debe ser fácil de implementar y no contener "todo menos la cocina". Si agrega AddRange, debe agregar InsertRangey RemoveRange(por simetría). Una mejor pregunta sería por qué no existen métodos de extensión para la IList<T>interfaz similares a la IEnumerable<T>interfaz. (métodos de extensión para en el lugar Sort, BinarySearch... sería útil)

xanatos
fuente
35
@ShdNx No es muy fácil implementarlos en términos de rendimiento. Un "interno" AddRange/RemoveRange/InsertRangepuede trabajar directamente en la colección "interna" y optimizar la Capacitygestión y utilizar métodos como Array.Copymover bloques de datos. Un método de extensión RemoveRangeprobablemente sería un orden de aumento más lento queList.RemoveRange
xanatos
2
Es una lástima que no hubiera (y todavía no) ninguna forma de que una IFoodeclaración de interfaz (p . Ej. ) Especifique un espacio de nombres "auxiliar" (p MyAssembly. Ej. ) Tal que si una clase afirma implementar IFoopero carece de método int Bar(String), el compilador generar método int IFoo.Bar(String p1) {return MyAssembly.ClassHelpers.IFoo.Bar(this, p1);} Si existiera tal característica, las interfaces podrían haber incluido más métodos como los AddRangeque podrían implementarse en términos de un comportamiento base, pero que algunas implementaciones podrían optimizar.
supercat
1
Se podrían implementar como métodos de extensión, de esa manera la implementación de la interfaz no tendría que implementarlos. ¿Por qué no lo son?
Tom Pažourek
15
Esto no tiene sentido. Una interfaz abstrae una implementación, de modo que puede haber múltiples implementaciones de las mismas características básicas; no hay ninguna razón por la que las funciones deban omitirse de una interfaz, porque la "implementación es difícil". Sin métodos como "AddRange" en la interfaz, no hay garantía de que el objeto subyacente los admita, y en ese momento se ve obligado a implementar una extensión subóptima o anular el propósito de usar una interfaz haciendo suposiciones peligrosas tratando de Cast a una clase de implementación específica. Las interfaces simplificadas se utilizan en exceso.
Triynko
3
Debe haber una interfaz IRangeList que admita operaciones masivas, implementada solo en algunas colecciones que internamente tendrán la implementación óptima.
también
8

Para aquellos que quieran tener métodos de extensión para "AddRange", "Sort", ... en IList,

A continuación se muestra el AddRangemétodo de extensión:

 public static void AddRange<T>(this IList<T> source, IEnumerable<T> newList)
 {
     if (source == null)
     {
        throw new ArgumentNullException(nameof(source));
     }

     if (newList == null)
     {
        throw new ArgumentNullException(nameof(newList));
     }

     if (source is List<T> concreteList)
     {
        concreteList.AddRange(newList);
        return;
     }

     foreach (var element in newList)
     {
        source.Add(element);
     }
}

Creé una pequeña biblioteca que hace esto. Lo encuentro más práctico que tener que rehacer sus métodos de extensión en cada proyecto.

Algunos métodos son más lentos que List, pero funcionan.

Aquí está el GitHub para interesarlos:

Repositorio de IListExtension

Emilien Mathieu
fuente