Обновить все объекты в коллекции с помощью LINQ - PullRequest
425 голосов
/ 30 декабря 2008

Есть ли способ сделать следующее с помощью LINQ?

foreach (var c in collection)
{
    c.PropertyToSet = value;
}

Чтобы уточнить, я хочу перебрать каждый объект в коллекции, а затем обновить свойство каждого объекта.

Мой вариант использования: у меня есть куча комментариев к сообщению в блоге, и я хочу перебрать каждый комментарий к сообщению в блоге и установить дату и время для сообщения в блоге равным +10 часов. Я мог бы сделать это в SQL, но я хочу сохранить его на бизнес-уровне.

Ответы [ 16 ]

746 голосов
/ 30 декабря 2008

Хотя вы можете использовать ForEach метод расширения, если вы хотите использовать только фреймворк, вы можете сделать

collection.Select(c => {c.PropertyToSet = value; return c;}).ToList();

ToList необходим для немедленной оценки выбора из-за отложенной оценки .

293 голосов
/ 22 апреля 2011
collection.ToList().ForEach(c => c.PropertyToSet = value);
62 голосов
/ 04 июня 2011

Я делаю это

Collection.All(c => { c.needsChange = value; return true; });
21 голосов
/ 30 декабря 2008

Я на самом деле нашел метод расширения , который будет делать то, что я хочу красиво

public static IEnumerable<T> ForEach<T>(
    this IEnumerable<T> source,
    Action<T> act)
{
    foreach (T element in source) act(element);
    return source;
}
12 голосов
/ 18 января 2013

Использование:

ListOfStuff.Where(w => w.Thing == value).ToList().ForEach(f => f.OtherThing = vauleForNewOtherThing);

Я не уверен, чрезмерно ли используется LINQ или нет, но это сработало для меня, когда я хотел обновить определенные элементы в списке для определенного условия.

6 голосов
/ 30 декабря 2008

Для этого не существует встроенного метода расширения. Хотя определение одного довольно просто. Внизу поста я определила метод Iterate. Может использоваться как

collection.Iterate(c => { c.PropertyToSet = value;} );

Итерация источника

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, (x, i) => callback(x));
}

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, callback);
}

private static void IterateHelper<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    int count = 0;
    foreach (var cur in enumerable)
    {
        callback(cur, count);
        count++;
    }
}
5 голосов
/ 17 августа 2010

Я попробовал несколько вариантов этого и продолжаю возвращаться к решению этого парня.

http://www.hookedonlinq.com/UpdateOperator.ashx

Опять же, это чужое решение. Но я собрал код в небольшую библиотеку и использую его довольно регулярно.

Я собираюсь вставить его код сюда, чтобы исключить вероятность того, что его сайт (блог) прекратит свое существование в будущем. (Нет ничего хуже, чем просмотр поста с надписью «Вот точный ответ, который вам нужен», «Клик» и «Мертвый URL».)

    public static class UpdateExtensions {

    public delegate void Func<TArg0>(TArg0 element);

    /// <summary>
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="update">The update statement to execute for each element.</param>
    /// <returns>The numer of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (update == null) throw new ArgumentNullException("update");
        if (typeof(TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        int count = 0;
        foreach (TSource element in source)
        {
            update(element);
            count++;
        }
        return count;
    }
}



int count = drawingObjects
        .Where(d => d.IsSelected && d.Color == Colors.Blue)
        .Update(e => { e.Color = Color.Red; e.Selected = false; } );
3 голосов
/ 30 декабря 2008

Мои 2 копейки: -

 collection.Count(v => (v.PropertyToUpdate = newValue) == null);
3 голосов
/ 30 декабря 2008

Нет, LINQ не поддерживает способ массового обновления. Единственный более короткий способ - использовать метод расширения ForEach - Почему в IEnumerable отсутствует метод расширения ForEach?

2 голосов
/ 25 июля 2018

Хотя вы специально спрашивали о linq-решении, и этот вопрос довольно старый, я выкладываю non-linq-решение. Это связано с тем, что linq (= встроенный язык query ) должен использоваться для запросов к коллекциям. Все linq-методы не изменяют базовую коллекцию, они просто возвращают новую (или, точнее, итератор новой коллекции). Таким образом, что бы вы ни делали, например Select не влияет на базовую коллекцию, вы просто получаете новую.

Конечно, вы могли бы сделать это с ForEach (что, кстати, не linq, а расширение List<T>). Но этот буквально использует foreach в любом случае, но с лямбда-выражением. Помимо этого каждый linq-метод внутренне выполняет итерацию вашей коллекции, например. используя foreach или for, однако он просто скрывает это от клиента. Я не считаю это более читабельным или обслуживаемым (подумайте о редактировании вашего кода при отладке метода, содержащего лямбда-выражения).

Сказав это, не используйте Linq для изменения предметов в вашей коллекции. Лучший способ - это решение, которое вы уже предоставили в своем вопросе. С помощью классического цикла вы можете легко перебирать свою коллекцию и обновлять ее элементы. На самом деле все эти решения, основанные на List.ForEach, ничем не отличаются, но гораздо труднее читать с моей точки зрения.

Так что вам не следует использовать linq в тех случаях, когда вы хотите обновить элементов вашей коллекции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...