немає AddRange()
методу для IList<T>
.
Як я можу додати список елементів до a, IList<T>
не перебираючи елементи та використовуючи Add()
метод?
немає AddRange()
методу для IList<T>
.
Як я можу додати список елементів до a, IList<T>
не перебираючи елементи та використовуючи Add()
метод?
Відповіді:
AddRange
визначається на List<T>
, а не на інтерфейсі.
Ви можете оголосити змінну List<T>
замість того, щоб IList<T>
або передати її List<T>
, щоб отримати доступ до AddRange
.
((List<myType>)myIList).AddRange(anotherList);
Це не є доброю практикою (див. Коментарі нижче), оскільки це IList<T>
може бути не a List<T>
, але якийсь інший тип, який реалізував інтерфейс і може дуже не мати AddRange
методу - у такому випадку ви дізнаєтесь лише тоді, коли ваш код викине виняток під час виконання.
Отже, якщо ви точно не знаєте, що тип справді такий, List<T>
вам не слід намагатися використовувати AddRange
.
Один із способів це зробити - перевірити тип за допомогою операторів is або як (з C # 7).
if(myIList is List<T>)
{
// can cast and AddRange
}
else
{
// iterate with Add
}
List<T>
(або, якщо це не вдалий вибір для вас, зробіть акторський склад там, де вам потрібно, щоб AddRange
він залишався локалізованим - це дуже дешева операція ).
InvalidCastException
використання, якщо що-небудь, крім List<T>
(масиву, наприклад).
Якщо подивитися на вихідний код c # для List , я думаю, List.AddRange () має оптимізації, які простий цикл не стосується. Отже, метод розширення повинен просто перевірити, чи є IList списком, і якщо так, використовуйте його власний AddRange ().
Оглядаючи вихідний код, ви бачите, що люди .NET роблять подібні речі у своїх власних розширеннях Linq для таких речей, як .ToList () (якщо це список, додайте його ... інакше створіть його).
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
в List<T>
два рази тут. Один з яких можна оптимізувати за допомогою as
ключового слова.
if (list is List<T> castedList) { castedList.AddRange(items); }
Ви можете зробити щось подібне:
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();
Отже, в основному ви б використовували Concat()
розширення та ToList()
отримували подібну функціональність, як AddRange()
.
Enumerable.Concat
реалізовано System.Linq.Enumerable
і повертається значення цього методу IEnumerable<TSource>
, тому я вважаю, що його не слід повертати назад IList<TSource>
- він може повернути щось інше через деталі реалізації, які ми не знаємо без перевірки вихідного коду - навіть незважаючи на те, що немає жодних гарантій, що це не зміниться - тому слід приділяти особливу увагу при підтримці декількох версій .NET.
Ви також можете написати метод розширення таким чином:
internal static class EnumerableHelpers
{
public static void AddRange<T>(this IList<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
}
Використання:
IList<int> collection = new int[10]; //Or any other IList
var items = new[] {1, 4, 5, 6, 7};
collection.AddRange(items);
Що все ще повторюється над елементами, але вам не потрібно писати ітерацію чи приворот кожного разу, коли ви її викликаєте.
Concat
, як відповів @Self_Taught_Programmer .