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?
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?
Odpowiedzi:
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
}
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);
}
}
}
}
list
do List<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łby ToList()
podobną funkcjonalność jak AddRange()
.
Enumerable.Concat
jest on implementowany przez System.Linq.Enumerable
i wartość zwracana przez tę metodę jest IEnumerable<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.
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);
Concat
Przesyłaj lub używaj LINQ , jak odpowiedział @Self_Taught_Programmer .