Подтвердить что ты не робот

Как добавить 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() для этой цели.

4b9b3361

Ответ 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; });