首页 文章

使用LINQ更新集合中的所有对象

提问于
浏览
394

有没有办法使用LINQ执行以下操作?

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

为了澄清,我想迭代集合中的每个对象,然后更新每个对象的属性 .

我的用例是我在博客文章中有一堆评论,我想在博客文章中迭代每个评论,并将博客帖子上的日期时间设置为10小时 . 我可以在SQL中完成它,但我想将它保留在业务层中 .

15 回答

  • 3

    虽然您可以使用 ForEach 扩展方法,但如果您只想使用框架,则可以执行此操作

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

    由于延迟评估,需要 ToList 才能立即评估选择 .

  • 683
    collection.ToList().ForEach(c => c.PropertyToSet = value);
    
  • 3

    我这样做

    Collection.All(c => { c.needsChange = value; return true; });
    
  • 0

    我实际上found an extension method会做我想要的

    public static IEnumerable<T> ForEach<T>(
        this IEnumerable<T> source,
        Action<T> act)
    {
        foreach (T element in source) act(element);
        return source;
    }
    
  • 4

    使用:

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

    我不确定这是否过度使用LINQ,但是当想要更新列表中特定条件的特定项时,它对我有用 .

  • 1

    没有内置的扩展方法来执行此操作 . 虽然定义一个是相当直接的 . 在帖子的底部是我定义的一个名为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

    我已经尝试了一些变化,我会继续回到这个人的解决方案 .

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

    再次,这是别人的解决方案 . 但我已将代码编译成一个小型库,并定期使用它 .

    我将在这里粘贴他的代码,因为他的网站(博客)在将来某个时候不再存在 . (没有什么比看到一篇帖子说“这是你需要的确切答案”,点击和死网更糟糕了 . )

    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; } );
    
  • 2

    不,LINQ不支持大规模更新方式 . 唯一更短的方法是使用 ForEach 扩展方法 - Why there is no ForEach extension method on IEnumerable?

  • 262

    我的2便士: -

    collection.Count(v => (v.PropertyToUpdate = newValue) == null);
    
  • 19

    我写了一些扩展方法来帮助我解决这个问题 .

    namespace System.Linq
    {
        /// <summary>
        /// Class to hold extension methods to Linq.
        /// </summary>
        public static class LinqExtensions
        {
            /// <summary>
            /// Changes all elements of IEnumerable by the change function
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="change">The way you want to change the stuff</param>
            /// <returns>An IEnumerable with all changes applied</returns>
            public static IEnumerable<T> Change<T>(this IEnumerable<T> enumerable, Func<T, T> change  )
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(change, "change");
    
                foreach (var item in enumerable)
                {
                    yield return change(item);
                }
            }
    
            /// <summary>
            /// Changes all elements of IEnumerable by the change function, that fullfill the where function
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="change">The way you want to change the stuff</param>
            /// <param name="where">The function to check where changes should be made</param>
            /// <returns>
            /// An IEnumerable with all changes applied
            /// </returns>
            public static IEnumerable<T> ChangeWhere<T>(this IEnumerable<T> enumerable, 
                                                        Func<T, T> change,
                                                        Func<T, bool> @where)
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(change, "change");
                ArgumentCheck.IsNullorWhiteSpace(@where, "where");
    
                foreach (var item in enumerable)
                {
                    if (@where(item))
                    {
                        yield return change(item);
                    }
                    else
                    {
                        yield return item;
                    }
                }
            }
    
            /// <summary>
            /// Changes all elements of IEnumerable by the change function that do not fullfill the except function
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="change">The way you want to change the stuff</param>
            /// <param name="where">The function to check where changes should not be made</param>
            /// <returns>
            /// An IEnumerable with all changes applied
            /// </returns>
            public static IEnumerable<T> ChangeExcept<T>(this IEnumerable<T> enumerable,
                                                         Func<T, T> change,
                                                         Func<T, bool> @where)
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(change, "change");
                ArgumentCheck.IsNullorWhiteSpace(@where, "where");
    
                foreach (var item in enumerable)
                {
                    if (!@where(item))
                    {
                        yield return change(item);
                    }
                    else
                    {
                        yield return item;
                    }
                }
            }
    
            /// <summary>
            /// Update all elements of IEnumerable by the update function (only works with reference types)
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="update">The way you want to change the stuff</param>
            /// <returns>
            /// The same enumerable you passed in
            /// </returns>
            public static IEnumerable<T> Update<T>(this IEnumerable<T> enumerable,
                                                   Action<T> update) where T : class
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(update, "update");
                foreach (var item in enumerable)
                {
                    update(item);
                }
                return enumerable;
            }
    
            /// <summary>
            /// Update all elements of IEnumerable by the update function (only works with reference types)
            /// where the where function returns true
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="update">The way you want to change the stuff</param>
            /// <param name="where">The function to check where updates should be made</param>
            /// <returns>
            /// The same enumerable you passed in
            /// </returns>
            public static IEnumerable<T> UpdateWhere<T>(this IEnumerable<T> enumerable,
                                                   Action<T> update, Func<T, bool> where) where T : class
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(update, "update");
                foreach (var item in enumerable)
                {
                    if (where(item))
                    {
                        update(item);
                    }
                }
                return enumerable;
            }
    
            /// <summary>
            /// Update all elements of IEnumerable by the update function (only works with reference types)
            /// Except the elements from the where function
            /// </summary>
            /// <param name="enumerable">The enumerable where you want to change stuff</param>
            /// <param name="update">The way you want to change the stuff</param>
            /// <param name="where">The function to check where changes should not be made</param>
            /// <returns>
            /// The same enumerable you passed in
            /// </returns>
            public static IEnumerable<T> UpdateExcept<T>(this IEnumerable<T> enumerable,
                                                   Action<T> update, Func<T, bool> where) where T : class
            {
                ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
                ArgumentCheck.IsNullorWhiteSpace(update, "update");
    
                foreach (var item in enumerable)
                {
                    if (!where(item))
                    {
                        update(item);
                    }
                }
                return enumerable;
            }
        }
    }
    

    我这样使用它:

    List<int> exampleList = new List<int>()
                {
                    1, 2 , 3
                };
    
            //2 , 3 , 4
            var updated1 = exampleList.Change(x => x + 1);
    
            //10, 2, 3
            var updated2 = exampleList
                .ChangeWhere(   changeItem => changeItem * 10,          // change you want to make
                                conditionItem => conditionItem < 2);    // where you want to make the change
    
            //1, 0, 0
            var updated3 = exampleList
                .ChangeExcept(changeItem => 0,                          //Change elements to 0
                              conditionItem => conditionItem == 1);     //everywhere but where element is 1
    

    参考参数检查:

    /// <summary>
    /// Class for doing argument checks
    /// </summary>
    public static class ArgumentCheck
    {
    
    
        /// <summary>
        /// Checks if a value is string or any other object if it is string
        /// it checks for nullorwhitespace otherwhise it checks for null only
        /// </summary>
        /// <typeparam name="T">Type of the item you want to check</typeparam>
        /// <param name="item">The item you want to check</param>
        /// <param name="nameOfTheArgument">Name of the argument</param>
        public static void IsNullorWhiteSpace<T>(T item, string nameOfTheArgument = "")
        {
    
            Type type = typeof(T);
            if (type == typeof(string) ||
                type == typeof(String))
            {
                if (string.IsNullOrWhiteSpace(item as string))
                {
                    throw new ArgumentException(nameOfTheArgument + " is null or Whitespace");
                }
            }
            else
            {
                if (item == null)
                {
                    throw new ArgumentException(nameOfTheArgument + " is null");
                }
            }
    
        }
    }
    
  • 2

    虽然你特意要求一个linq解决方案,但这个问题已经很久了,我发布了一个非linq解决方案 . 这是因为linq(= lanuguage integrated query )用于集合查询 . 所有linq方法都不会修改底层集合,它们只返回一个新集合(或更精确的迭代器到新集合) . 无论你做什么,例如使用 Select 不会影响基础集合,您只需获得一个新集合 .

    当然你可以使用 ForEach (顺便说一句,这不是linq,而是 List<T> 的扩展名) . 但是这个字面意思是使用 foreach 但是使用lambda表达式 . 除此之外,每个linq方法都在内部迭代您的集合,例如通过使用 foreachfor ,它只是将其隐藏在客户端 . 我认为这不再具有可读性和可维护性(想想在调试包含lambda表达式的方法时编辑代码) .

    说完之后不要使用Linq来修改你馆藏中的物品 . 更好的方法是您在问题中提供的解决方案 . 使用经典循环,您可以轻松迭代您的收藏并更新其项目 . 事实上,依赖于 List.ForEach 的所有这些解决方案都没有什么不同,但从我的角度来看却难以理解 .

    因此,在您想要更新集合元素的情况下,不应该使用linq .

  • 11

    您可以使用LINQ将集合转换为数组,然后调用Array.ForEach():

    Array.ForEach(MyCollection.ToArray(), item=>item.DoSomeStuff());
    

    显然,这不适用于结构集合或内置类型(如整数或字符串) .

  • 1

    这是我使用的扩展方法...

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

    您可以使用Magiq,LINQ的批处理操作框架 .

  • 55

    我假设您要更改查询中的值,以便为其编写函数

    void DoStuff()
    {
        Func<string, Foo, bool> test = (y, x) => { x.Bar = y; return true; };
        List<Foo> mylist = new List<Foo>();
        var v = from x in mylist
                where test("value", x)
                select x;
    }
    
    class Foo
    {
        string Bar { get; set; }
    }
    

    但如果这就是你的意思,那不是舒尔 .

相关问题