Współpracownik zapytał mnie dzisiaj, jak dodać zakres do kolekcji. Ma klasę, która dziedziczy Collection<T>
. Istnieje właściwość get-only tego typu, która zawiera już pewne elementy. Chce dodać elementy z innej kolekcji do kolekcji właściwości. Jak może to zrobić w sposób przyjazny dla C # 3? (Zwróć uwagę na ograniczenie dotyczące właściwości get-only, które zapobiega rozwiązaniom takim jak wykonywanie Union i ponowne przypisywanie).
Jasne, foreach z Property. Dodaj zadziała. Ale List<T>
AddRange w stylu a byłby znacznie bardziej elegancki.
Łatwo jest napisać metodę rozszerzającą:
public static class CollectionHelpers
{
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
Ale mam wrażenie, że wymyślam koło na nowo. Nie znalazłem nic podobnego w System.Linq
lub morelinq .
Zły projekt? Po prostu zadzwoń Dodaj? Brakuje oczywistości?
c#
collections
c#-3.0
extension-methods
TrueWill
źródło
źródło
ICollection<T>
Wydaje się, że jeden problem nie maAdd
metody. msdn.microsoft.com/en-us/library/… JednakCollection<T>
ma jeden.Add(T item)
w ogóle mieć ? Wydaje się, że jest to niedopracowane podejście do oferowania możliwości dodania pojedynczego elementu, a następnie oczekiwania, że wszyscy dzwoniący będą iterować, aby dodać więcej niż jeden naraz. Twoje stwierdzenie z pewnością jest prawdziwe,IEnumerable<T>
ale nieraz byłem sfrustrowanyICollections
. Nie zgadzam się z tobą, po prostu wyładowuję.Odpowiedzi:
Nie, wydaje się to całkiem rozsądne. Istnieje metoda
List<T>.
AddRange () , która w zasadzie właśnie to robi, ale wymaga, aby Twoja kolekcja była konkretnaList<T>
.źródło
Spróbuj rzutować na List w metodzie rozszerzenia przed uruchomieniem pętli. W ten sposób możesz wykorzystać wydajność List.AddRange.
źródło
as
Operator nigdy nie rzuci. Jeślidestination
nie można rzutować,list
będzie miał wartość null ielse
blok zostanie wykonany.if (destination is List<T> list)
Ponieważ
.NET4.5
jeśli chcesz mieć jedną linijkę, możesz użyćSystem.Collections.Generic
ForEach.lub nawet krócej jak
Pod względem wydajności jest taki sam jak dla każdej pętli (cukier syntaktyczny).
Również nie spróbować go jak przypisywanie
przyczyna
ForEach
jest nieważna.Edycja: skopiowane z komentarzy, opinia Liperta na temat ForEach
źródło
ForEach
wydaje się być zdefiniowany tylko naList<T>
, nieCollection
?Pamiętaj, że każdy
Add
sprawdzi pojemność kolekcji i zmieni jej rozmiar w razie potrzeby (wolniej). ZaAddRange
pomocą kolekcji zostanie ustawiona pojemność, a następnie dodane elementy (szybciej). Ta metoda rozszerzenia będzie bardzo powolna, ale zadziała.źródło
Oto nieco bardziej zaawansowana / gotowa do produkcji wersja:
źródło
destination
jest to listaShape
, klasa abstrakcyjna.source
jest listąCircle
dziedziczonych klas.Wszystkie klasy C5 Generic Collections Library obsługują tę
AddRange
metodę. C5 ma znacznie bardziej niezawodny interfejs, który w rzeczywistości ujawnia wszystkie funkcje swoich podstawowych implementacji i jest zgodny z interfejsamiSystem.Collections.Generic
ICollection
iIList
, co oznacza, że teC5
kolekcje można łatwo zastąpić jako podstawową implementację.źródło
Możesz dodać swój zakres IEnumerable do listy, a następnie ustawić ICollection = na listę.
źródło
Lub możesz po prostu utworzyć takie rozszerzenie ICollection:
Używanie go byłoby jak używanie go na liście:
źródło