ДобавитьRange в коллекцию
Сотрудник спросил меня, как добавить диапазон в коллекцию. У него есть класс, который наследуется от Collection<T>
. Там свойство get-only этого типа, которое уже содержит некоторые элементы. Он хочет добавить элементы в другую коллекцию к коллекции свойств. Как он может сделать это в стиле С# 3? (Обратите внимание на ограничение свойства get-only, которое предотвращает такие решения, как объединение и переназначение.)
Конечно, foreach с Property. Добавить будет работать. Но a List<T>
-style AddRange был бы намного более изящным.
Достаточно легко написать метод расширения:
public static class CollectionHelpers
{
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
Но у меня такое чувство, что я изобретаю колесо. Я не нашел ничего подобного в System.Linq
или morelinq.
Плохой дизайн? Просто позвоните Добавить? Отсутствует очевидное?
Ответы
Ответ 2
Попробуйте выполнить листинг в List в методе расширения до запуска цикла. Таким образом, вы можете воспользоваться преимуществами List.AddRange.
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
List<T> list = destination as List<T>;
if (list != null)
{
list.AddRange(source);
}
else
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
Ответ 3
Так как .NET4.5
, если вы хотите, чтобы один лайнер вы можно использовать System.Collections.Generic
ForEach.
source.ForEach(o => destination.Add(o));
или даже короче, чем
source.ForEach(destination.Add);
По производительности он будет таким же, как для каждого цикла (синтаксический сахар).
Также не попробуйте назначить его как
var x = source.ForEach(destination.Add)
причина ForEach
недействительна.
Ответ 4
Помните, что каждый Add
будет проверять емкость коллекции и изменять ее по мере необходимости (медленнее). С помощью AddRange
в коллекции будет задана емкость, а затем добавлены элементы (быстрее). Этот метод расширения будет очень медленным, но будет работать.
Ответ 5
Классы C5 Generic Collections Library поддерживают метод AddRange
. C5 имеет гораздо более надежный интерфейс, который фактически раскрывает все функции его основных реализаций и совместим с интерфейсами System.Collections.Generic
ICollection
и IList
, что означает, что коллекции C5
могут быть легко заменены как базовые реализация.
Ответ 6
Вы можете добавить свой диапазон IEnumerable в список, а затем установить ICollection = в список.
IEnumerable<T> source;
List<item> list = new List<item>();
list.AddRange(source);
ICollection<item> destination = list;
Ответ 7
Или вы можете просто сделать расширение ICollection следующим образом:
public static ICollection<T> AddRange<T>(this ICollection<T> @this, IEnumerable<T> items)
{
foreach(var item in items)
{
@this.Add(item);
}
return @this;
}
Использовать его было бы так же, как использовать его в списке:
collectionA.AddRange(IEnumerable<object> items);
Ответ 8
Вот немного более продвинутая/готовая к производству версия:
public static class CollectionExtensions
{
public static TCol AddRange<TCol, TItem>(this TCol destination, IEnumerable<TItem> source)
where TCol : ICollection<TItem>
{
if(destination == null) throw new ArgumentNullException(nameof(destination));
if(source == null) throw new ArgumentNullException(nameof(source));
// don't cast to IList to prevent recursion
if (destination is List<TItem> list)
{
list.AddRange(source);
return destination;
}
foreach (var item in source)
{
destination.Add(item);
}
return destination;
}
}