nie ma na to AddRange()
metody IList<T>
.
Jak mogę dodać listę elementów do a IList<T>
bez iteracji po elementach i używania Add()
metody?
źródło
nie ma na to AddRange()
metody IList<T>
.
Jak mogę dodać listę elementów do a IList<T>
bez iteracji po elementach i używania Add()
metody?
AddRange
jest zdefiniowany w List<T>
interfejsie, a nie w interfejsie.
Możesz zadeklarować zmienną jako List<T>
zamiast IList<T>
lub rzutować ją na List<T>
, aby uzyskać dostęp do AddRange
.
((List<myType>)myIList).AddRange(anotherList);
To nie jest dobra praktyka (patrz komentarze poniżej), ponieważ IList<T>
może nie być a List<T>
, ale jakiś inny typ, który zaimplementował interfejs i może bardzo nie mieć AddRange
metody - w takim przypadku dowiesz się tylko, gdy twój kod wyrzuci wyjątek w czasie wykonywania.
Tak więc, chyba że wiesz na pewno, że typ jest rzeczywiście typem, List<T>
którego nie powinieneś próbować używać AddRange
.
Jednym ze sposobów jest przetestowanie typu za pomocą operatorów is lub as (od C # 7).
if(myIList is List<T>)
{
// can cast and AddRange
}
else
{
// iterate with Add
}
Concat
Przesyłaj lub używaj LINQ , jak odpowiedział @Self_Taught_Programmer .List<T>
(lub, jeśli nie jest to dobry wybór, wykonaj rzutowanie tam, gdzie chcesz,AddRange
aby był zlokalizowany - jest to operacja bardzo tania ).InvalidCastException
jeśli zostanie użyte na czymkolwiek innym niżList<T>
(na przykład tablica).Jeśli spojrzysz na kod źródłowy C # dla List , myślę, że List.AddRange () ma optymalizacje, których nie rozwiązuje prosta pętla. Tak więc metoda rozszerzająca powinna po prostu sprawdzić, czy IList jest Listą, a jeśli tak, użyj jej natywnej AddRange ().
Przeglądając kod źródłowy, widzisz, że ludzie .NET robią podobne rzeczy we własnych rozszerzeniach Linq dla rzeczy takich jak .ToList () (jeśli jest to lista, rzuć ją ... w przeciwnym razie utwórz ją).
public static class IListExtension { public static void AddRange<T>(this IList<T> list, IEnumerable<T> items) { if (list == null) throw new ArgumentNullException(nameof(list)); if (items == null) throw new ArgumentNullException(nameof(items)); if (list is List<T> asList) { asList.AddRange(items); } else { foreach (var item in items) { list.Add(item); } } } }
źródło
list
doList<T>
dwóch razy tutaj. Jeden z nich można zoptymalizować za pomocąas
słowa kluczowego.if (list is List<T> castedList) { castedList.AddRange(items); }
Możesz zrobić coś takiego:
IList<string> oIList1 = new List<string>{"1","2","3"}; IList<string> oIList2 = new List<string>{"4","5","6"}; IList<string> oIList3 = oIList1.Concat(oIList2).ToList();
Zasadniczo używałbyś
Concat()
rozszerzenia i uzyskałbyToList()
podobną funkcjonalność jakAddRange()
.Źródło
źródło
Enumerable.Concat
jest on implementowany przezSystem.Linq.Enumerable
i wartość zwracana przez tę metodę jestIEnumerable<TSource>
taka, więc uważam, że nie powinno się jej odwracaćIList<TSource>
- może zwrócić coś innego z powodu szczegółów implementacji, których nie znamy bez sprawdzenia kodu źródłowego - mimo to nie ma gwarancji, że to się nie zmieni - dlatego należy zwrócić szczególną uwagę na obsługę wielu wersji .NET.Możesz również napisać taką metodę rozszerzającą:
internal static class EnumerableHelpers { public static void AddRange<T>(this IList<T> collection, IEnumerable<T> items) { foreach (var item in items) { collection.Add(item); } } }
Stosowanie:
IList<int> collection = new int[10]; //Or any other IList var items = new[] {1, 4, 5, 6, 7}; collection.AddRange(items);
Co nadal jest iteracją po elementach, ale nie musisz pisać iteracji ani rzutować za każdym razem, gdy ją wywołasz.
źródło
Inna odpowiedź za pomocą LINQ, pod warunkiem, że dodawana rzecz to a
List<T>
lub możesz do niej zadzwonićToList()
:IEnumerable<string> toAdd = new string[] {"a", "b", "c"}; IList<string> target = new List<string>(); toAdd.ToList().ForEach(target.Add);
źródło