Как добавить IEnumerable <T> в существующий ICollection <T>
Учитывая существующий экземпляр ICollection<T>
(например, dest
), что является наиболее эффективным и читаемым способом добавления элементов из IEnumerable<T>
?
В моем случае использования у меня есть какой-то метод утилиты Collect(IEnumerable items)
, который возвращает новый ICollection
с элементами из items
, поэтому я делаю это следующим образом:
public static ICollection<T> Collect<T>(IEnumerable<T> items) where T:ICollection<T>
{
...
ICollection<T> dest = Activator.CreateInstance<T>();
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
...
return dest;
}
Вопрос: есть ли какой-либо "лучший" способ (более эффективный или читаемый))?
ОБНОВЛЕНИЕ. Я думаю, что использование Aggregate()
довольно свободно и не так неэффективно, как вызов ToList().ForEach()
. Но это не очень читаемо. Поскольку никто не согласен с использованием Aggregate()
, я хотел бы прочитать ваши причины, чтобы НЕ использовать Aggregate()
для этой цели.
Ответы
Ответ 1
Просто используйте Enumerable.Concat
:
IEnumerable<YourType> result = dest.Concat(items);
Если вы хотите использовать List<T>
, используйте ToList
:
List<YourType> result = dest.Concat(items).ToList();
// perhaps:
dest = result;
Если dest
на самом деле уже есть список, и вы хотите его изменить, используйте AddRange
:
dest.AddRange(items);
Обновить:
если вам нужно добавить элементы в аргумент метода ICollection<T>
, вы можете использовать это расширение:
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> seq)
{
List<T> list = collection as List<T>;
if (list != null)
list.AddRange(seq);
else
{
foreach (T item in seq)
collection.Add(item);
}
}
//...
public static void Foo<T>(ICollection<T> dest)
{
IEnumerable<T> items = ...
dest.AddRange(items);
}
Ответ 2
Лично я бы пошел с комментарием @ckruczek цикла foreach
:
foreach (var item in items)
dest.Add(item);
Простой, чистый, и почти все сразу понимают, что он делает.
Если вы настаиваете на вызове метода, скрывающем цикл, тогда некоторые люди определяют собственный метод расширения foreach
для IEnumerable<T>
, аналогичный тому, что определено для List<T>
. Реализация тривиальна:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
if (source == null) throw new ArgumentNullException(nameof(source));
if (action == null) throw new ArgumentNullException(nameof(action));
foreach (item in source)
action(item);
}
Учитывая, что вы могли бы написать
items.ForEach(dest.Add);
Я не вижу в этом большой пользы, но никаких недостатков тоже.
Ответ 3
Мы на самом деле написали для этого метод расширения (наряду с кучей других методов расширения ICollection):
public static class CollectionExt
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
Contract.Requires(collection != null);
Contract.Requires(source != null);
foreach (T item in source)
{
collection.Add(item);
}
}
}
Поэтому мы можем просто использовать AddRange()
на ICollection()
:
ICollection<int> test = new List<int>();
test.AddRange(new [] {1, 2, 3});
Примечание. Если вы хотите использовать List<T>.AddRange()
, если базовая коллекция имеет тип List<T>
, вы можете реализовать метод расширения следующим образом:
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
var asList = collection as List<T>;
if (asList != null)
{
asList.AddRange(source);
}
else
{
foreach (T item in source)
{
collection.Add(item);
}
}
}
Ответ 4
items.ToList().ForEach(dest.Add);
Если вы не хотите создавать новый экземпляр коллекции, создайте метод расширения.
public static class Extension
{
public static void AddRange<T>(this ICollection<T> source, IEnumerable<T> items)
{
if (items == null)
{
return;
}
foreach (T item in items)
{
source.Add(item);
}
}
}
Затем вы можете редактировать свой код следующим образом:
ICollection<T> dest = ...;
IEnumerable<T> items = ...;
dest.AddRange(items);
Ответ 5
Самый эффективный:
foreach(T item in itens) dest.Add(item)
Наиболее читаемый (, но неэффективный, потому что он создает броский список):
items.ToList().ForEach(dest.Add);
Менее читаемый, но не такой неэффективный:
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });