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?

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)


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.