Dlaczego IList nie obsługuje AddRange

89

List.AddRange()istnieje, ale IList.AddRange()nie ma.
Wydaje mi się to dziwne. Jaki jest tego powód?

Boris Callens
źródło

Odpowiedzi:

68

Ponieważ interfejs powinien być łatwy w implementacji i nie zawierać „wszystkiego oprócz kuchni”. Jeśli dodasz AddRange, powinieneś dodać InsertRangei RemoveRange(dla symetrii). Lepszym pytaniem byłoby, dlaczego nie ma metod rozszerzających IList<T>interfejsu podobnych do IEnumerable<T>interfejsu. (metody szkoleniowe dla in-place Sort, BinarySearch... byłoby przydatne)

xanatos
źródło
35
@ShdNx Nie są one zbyt trywialne w implementacji pod względem wydajności. „Wewnętrzny” AddRange/RemoveRange/InsertRangemoże pracować bezpośrednio na „wewnętrznym” zbiorze i optymalizować Capacityzarządzanie oraz wykorzystywać takie metody, jak Array.Copyporuszanie się po blokach danych. Metoda przedłużenia RemoveRangebyłaby prawdopodobnie o rząd wielkości wolniejsza niżList.RemoveRange
Xanatos
2
Szkoda, że ​​nie było (i nadal nie jest) w żaden sposób IFoodeklaracja interfejsu (np. ), Aby określić przestrzeń nazw „pomocnika” (np. MyAssembly) W taki sposób, że jeśli klasa twierdzi, że jest zaimplementowana, IFooale nie ma metody int Bar(String), kompilator automatycznie metoda generowania int IFoo.Bar(String p1) {return MyAssembly.ClassHelpers.IFoo.Bar(this, p1);} Gdyby taka funkcja istniała, interfejsy mogłyby zawierać więcej metod, takich jak te, AddRangektóre mogłyby zostać zaimplementowane w zakresie zachowania podstawowego, ale które niektóre implementacje mogłyby zoptymalizować.
supercat
1
Mogłyby zostać zaimplementowane jako metody rozszerzające, dzięki czemu implementacja interfejsu nie musiałaby ich implementować. Dlaczego tak nie jest?
Tom Pažourek
15
To nie ma sensu. Interfejs wyodrębnia implementację, tak że może istnieć wiele implementacji tych samych podstawowych funkcji; nie ma powodu, aby pominąć funkcje w interfejsie, ponieważ „implementacja jest trudna”. Bez metod takich jak „AddRange” w interfejsie nie ma gwarancji, że bazowy obiekt je obsługuje i w tym momencie jesteś zmuszony albo zaimplementować nieoptymalne rozszerzenie, albo pokonać cel używania interfejsu, podejmując niebezpieczne założenia rzutowane na określoną klasę implementującą. Nieuczciwe interfejsy są nadużywane.
Triynko,
3
Powinien istnieć interfejs IRangeList obsługujący operacje masowe, zaimplementowany tylko na niektórych kolekcjach, które wewnętrznie będą miały optymalną implementację.
też
8

Dla tych, którzy chcą mieć metody rozszerzające dla „AddRange”, „Sort”, ... na IList,

Poniżej znajduje się AddRangemetoda rozszerzenia:

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

Stworzyłem małą bibliotekę, która to robi. Uważam, że jest to bardziej praktyczne niż konieczność ponownego modyfikowania metod rozszerzania w każdym projekcie.

Niektóre metody są wolniejsze niż lista, ale spełniają swoje zadanie.

Oto GitHub, który ich zainteresuje:

Repozytorium IListExtension

Emilien Mathieu
źródło