Actualice todos los objetos en una colección usando LINQ

¿Hay alguna manera de hacer lo siguiente con LINQ?

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

Para aclarar, quiero iterar a través de cada objeto en una colección y luego actualizar una propiedad en cada objeto.

Mi caso de uso es que tengo un montón de comentarios en una publicación de blog, y quiero repetir cada comentario en una publicación de blog y establecer la fecha y hora en la publicación del blog en +10 horas. Podría hacerlo en SQL, pero quiero mantenerlo en la capa de negocios.

Si bien puede usar un método de extensión ForEach , si desea usar solo el marco, puede hacerlo

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

ToList es necesario para evaluar la selección inmediatamente debido a la evaluación perezosa .

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

yo estoy haciendo esto

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

De hecho, encontré un método de extensión que hará lo que quiero muy bien

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

Utilizar:

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

No estoy seguro de si esto es demasiado uso de LINQ o no, pero me ha funcionado cuando quería actualizar un elemento específico de la lista para una condición específica.

No hay un método de extensión incorporado para hacer esto. Aunque definir uno es bastante sencillo. En la parte inferior de la publicación hay un método que definí llamado Iterate. Se puede usar como tal

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

Fuente de iteración

 public static void Iterate(this IEnumerable enumerable, Action callback) { if (enumerable == null) { throw new ArgumentNullException("enumerable"); } IterateHelper(enumerable, (x, i) => callback(x)); } public static void Iterate(this IEnumerable enumerable, Action callback) { if (enumerable == null) { throw new ArgumentNullException("enumerable"); } IterateHelper(enumerable, callback); } private static void IterateHelper(this IEnumerable enumerable, Action callback) { int count = 0; foreach (var cur in enumerable) { callback(cur, count); count++; } } 

Intenté algunas variaciones sobre esto, y sigo volviendo a la solución de este tipo.

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

De nuevo, esta es la solución de otra persona. Pero compilé el código en una pequeña biblioteca y lo uso con bastante regularidad.

Voy a pegar su código aquí, por la posibilidad de que su sitio (blog) deje de existir en algún momento en el futuro. (No hay nada peor que ver una publicación que dice “Aquí está la respuesta exacta que necesita”, haga clic en, y URL muerta).

  public static class UpdateExtensions { public delegate void Func(TArg0 element); ///  /// Executes an Update statement block on all elements in an IEnumerable sequence. ///  /// The source element type. /// The source sequence. /// The update statement to execute for each element. /// The numer of records affected. public static int Update(this IEnumerable source, Func 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; } ); 

No, LINQ no es compatible con una forma de actualización masiva. La única forma más corta sería usar un método de extensión ForEach : ¿por qué no hay un método de extensión ForEach en IEnumerable?

Mis 2 centavos: –

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

Escribí algunos métodos de extensión para ayudarme con eso.

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

Lo estoy usando así:

  List exampleList = new List() { 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 

Para referencia la verificación de argumento:

 ///  /// Class for doing argument checks ///  public static class ArgumentCheck { ///  /// Checks if a value is string or any other object if it is string /// it checks for nullorwhitespace otherwhise it checks for null only ///  /// Type of the item you want to check /// The item you want to check /// Name of the argument public static void IsNullorWhiteSpace(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"); } } } } 

Aquí está el método de extensión que uso …

  ///  /// Executes an Update statement block on all elements in an IEnumerable of T /// sequence. ///  /// The source element type. /// The source sequence. /// The action method to execute for each element. /// The number of records affected. public static int Update(this IEnumerable source, Func 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; } 

Puede utilizar Magiq , un marco de trabajo por lotes para LINQ.

Aunque usted solicitó específicamente una solución de linq y esta pregunta es bastante antigua, publico una solución que no es linq. Esto se debe a que la consulta integrada de linq (= lanuguage) se utiliza para consultas en colecciones. Todos los linq-methods no modifican la colección subyacente, solo devuelven una nueva (o un iterador más preciso a una nueva colección). Por lo tanto, cualquier cosa que hagas, por ejemplo, con un Select no afecta a la colección subyacente, simplemente obtienes una nueva.

Por supuesto, puedes hacerlo con un ForEach (que no es linq, por cierto, sino una extensión de List ). Pero esto literalmente usa foreach todos modos pero con una expresión lambda. Aparte de esto, cada método de linq itera internamente su colección, por ejemplo, utilizando foreach o for , sin embargo, simplemente lo oculta del cliente. No considero esto más legible ni mantenible (piense en editar su código mientras depura un método que contiene expresiones lambda).

Habiendo dicho esto, no se debe usar Linq para modificar elementos en su colección. Una mejor manera es la solución que ya proporcionó en su pregunta. Con un loop clásico, puede iterar fácilmente su colección y actualizar sus elementos. De hecho, todas las soluciones que dependen de List.ForEach no son nada diferentes, pero son mucho más difíciles de leer desde mi perspectiva.

Por lo tanto, no debe usar linq en aquellos casos en los que desee actualizar los elementos de su colección.

Supongo que quieres cambiar los valores dentro de una consulta para que puedas escribir una función para ella

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

Pero no lo creo si esto es lo que quieres decir.

Puede usar LINQ para convertir su colección a una matriz y luego invocar Array.ForEach ():

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

Obviamente, esto no funcionará con colecciones de estructuras o tipos incorporados como enteros o cadenas.