Me gustaría hacer el equivalente de lo siguiente en LINQ, pero no puedo entender cómo:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
¿Cuál es la sintaxis real?
linq
foreach
ienumerable
etiquetas2k
fuente
fuente
ForEach()
.ForEach
extensión .foreach (var i in items) i.Dostuff();
Respuestas:
No hay extensión ForEach para
IEnumerable
; sólo paraList<T>
. Entonces podrías hacerAlternativamente, escriba su propio método de extensión ForEach:
fuente
IENumerable<T>
en el método de extensión. Me gusta:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Fredrik ha proporcionado la solución, pero puede valer la pena considerar por qué esto no está en el marco para empezar. Creo que la idea es que los operadores de consulta LINQ no deberían tener efectos secundarios, y que se ajusten a una forma razonablemente funcional de ver el mundo. Claramente, ForEach es exactamente lo contrario: una construcción puramente basada en efectos secundarios.
Eso no quiere decir que sea algo malo, solo pensar en las razones filosóficas detrás de la decisión.
fuente
Seq.iter
no devuelve nada, y mucho menos una nueva secuencia con elementos de efectos secundarios. Realmente se trata solo de los efectos secundarios. Puede estar pensandoSeq.map
, porqueSeq.iter
es precisamente equivalente a unForEach
método de extensión enIEnumerabe<_>
.Actualización 17/07/2012: Aparentemente a partir de C # 5.0, el comportamiento
foreach
descrito a continuación ha cambiado y " el uso de unaforeach
variable de iteración en una expresión lambda anidada ya no produce resultados inesperados " . Esta respuesta no se aplica a C # ≥ 5.0 .@John Skeet y todos los que prefieren la palabra clave foreach.
El problema con "foreach" en C # anterior a 5.0 , es que es inconsistente con la forma en que el equivalente "para la comprensión" funciona en otros idiomas, y con cómo esperaría que funcionara (la opinión personal aquí se menciona solo porque otros han mencionado su opinión sobre la legibilidad). Consulte todas las preguntas sobre " Acceso al cierre modificado ", así como " Cierre sobre la variable de bucle considerado dañino ". Esto es solo "dañino" debido a la forma en que se implementa "foreach" en C #.
Tome los siguientes ejemplos utilizando el método de extensión funcionalmente equivalente al de la respuesta de @Fredrik Kalseth.
Disculpas por el ejemplo excesivamente inventado. Solo estoy usando Observable porque no es del todo descabellado hacer algo como esto. Obviamente, hay mejores formas de crear este observable, solo estoy tratando de demostrar un punto. Por lo general, el código suscrito al observable se ejecuta de forma asíncrona y potencialmente en otro hilo. Si usa "foreach", esto podría producir resultados muy extraños y potencialmente no deterministas.
La siguiente prueba con el método de extensión "ForEach" pasa:
Lo siguiente falla con el error:
Esperado: equivalente a <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> Pero fue: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9>
fuente
Puede usar la
FirstOrDefault()
extensión, que está disponible paraIEnumerable<T>
. Al regresarfalse
del predicado, se ejecutará para cada elemento, pero no le importará que en realidad no encuentre una coincidencia. Esto evitará losToList()
gastos generales.fuente
foreach(Item i in GetItems()) { i.DoStuff();}
tomar más personajes y hacerlo extremadamente confusoitems.All(i => { i.DoStuff(); return true; }
Tomé el método de Fredrik y modifiqué el tipo de retorno.
De esta manera, el método admite la ejecución diferida como otros métodos LINQ.
EDITAR: Si esto no estaba claro, cualquier uso de este método debe terminar con ToList () o cualquier otra forma de forzar el método para que funcione en el enumerable completo. De lo contrario, la acción no se realizaría.
Y aquí está la prueba para ayudar a verlo:
Si elimina ToList () al final, verá que la prueba falla ya que StringBuilder contiene una cadena vacía. Esto se debe a que ningún método obligó a ForEach a enumerar.
fuente
ForEach
es interesante, sin embargo, no coincide con el comportamiento deList.ForEach
, cuya firma espublic void ForEach(Action<T> action)
. Tampoco coincide con el comportamiento de laObservable.ForEach
extensiónIObservable<T>
, cuya firma espublic static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
. FWIW, elForEach
equivalente en las colecciones de Scala, incluso las que son perezosas, también tienen un tipo de retorno que es equivalente a vacío en C #.Select
conToList
. El propósito deForEach
es no tener que llamarToList
. Debe ejecutarse de inmediato.Mantenga sus efectos secundarios fuera de mi IEnumerable
Como otros han señalado aquí y en el extranjero
IEnumerable
, se espera que LINQ y los métodos estén libres de efectos secundarios.¿Realmente quiere "hacer algo" a cada elemento en el IEnumerable? Entonces
foreach
es la mejor opción. La gente no se sorprende cuando ocurren efectos secundarios aquí.Apuesto a que no quieres un efecto secundario
Sin embargo, en mi experiencia, generalmente no se requieren efectos secundarios. La mayoría de las veces hay una simple consulta LINQ esperando ser descubierta acompañada de una respuesta de StackOverflow.com de Jon Skeet, Eric Lippert o Marc Gravell que explica cómo hacer lo que quiere.
Algunos ejemplos
Si en realidad solo está agregando (acumulando) algún valor, entonces debe considerar el
Aggregate
método de extensión.Quizás desee crear uno nuevo a
IEnumerable
partir de los valores existentes.O tal vez desee crear una tabla de búsqueda:
La lista (juego de palabras no del todo previsto) de posibilidades sigue y sigue.
fuente
Si desea actuar como las listas de enumeración, debe ceder cada elemento.
fuente
Hay una versión experimental de Microsoft de Interactive Extensions para LINQ (también en NuGet , consulte el perfil de RxTeams para obtener más enlaces). El video del Canal 9 lo explica bien.
Sus documentos solo se proporcionan en formato XML. He ejecutado esta documentación en Sandcastle para permitir que esté en un formato más legible. Descomprima el archivo de documentos y busque index.html .
Entre muchas otras cosas, proporciona la implementación esperada de ForEach. Te permite escribir código como este:
fuente
Según PLINQ (disponible desde .Net 4.0), puede hacer un
hacer un bucle foreach paralelo en un IEnumerable.
fuente
El propósito de ForEach es causar efectos secundarios. IEnumerable es para la enumeración diferida de un conjunto.
Esta diferencia conceptual es bastante visible cuando la consideras.
SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));
Esto no se ejecutará hasta que haga un "conteo" o una "Lista ()" o algo así. Claramente no es lo que se expresa.
Debe usar las extensiones IEnumerable para configurar cadenas de iteración, definiendo el contenido por sus respectivas fuentes y condiciones. Los árboles de expresión son poderosos y eficientes, pero debes aprender a apreciar su naturaleza. Y no solo para programar a su alrededor para salvar algunos caracteres que anulan la evaluación perezosa.
fuente
Mucha gente lo mencionó, pero tuve que escribirlo. ¿No es esto más claro / más legible?
Corto y simple (st).
fuente
GetItems()
método devuelve.foreach (var item in GetItems()) item.DoStuff();
es solo una belleza.Ahora tenemos la opción de ...
Por supuesto, esto abre una nueva lata de gusanos de hilo.
ps (Perdón por las fuentes, es lo que decidió el sistema)
fuente
Como ya señalan numerosas respuestas, usted mismo puede agregar fácilmente dicho método de extensión. Sin embargo, si no desea hacer eso, aunque no estoy al tanto de algo así en el BCL, todavía hay una opción en el
System
espacio de nombres, si ya tiene una referencia a la Extensión reactiva (y si no , Deberías):Aunque los nombres de los métodos son un poco diferentes, el resultado final es exactamente lo que está buscando.
fuente
ForEach también se puede encadenar , solo vuelve a ponerlo en la pila después de la acción. mantener fluidez
Una versión ansiosa de implementación.
Editar: una versión perezosa está utilizando rendimiento de rendimiento, como este .
La versión Lazy NECESITA materializarse, ToList () por ejemplo, de lo contrario, no pasa nada. vea abajo los excelentes comentarios de ToolmakerSteve.
Mantengo ForEach () y ForEachLazy () en mi biblioteca.
fuente
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
? Un solo bucle explícito. Supongo que si era importante hacer todas las acciones1 ANTES de comenzar a hacer las acciones2.ProcessShipping()
? ¿Envía un correo electrónico al comprador, carga su tarjeta de crédito, pero nunca le envía sus cosas? Ciertamente preguntando por problemas.Esta abstracción de "enfoque funcional" se escapa a lo grande. Nada en el nivel del idioma previene los efectos secundarios. Siempre que pueda hacer que llame a su lambda / delegado para cada elemento en el contenedor, obtendrá el comportamiento "ForEach".
Aquí, por ejemplo, una forma de fusionar srcDictionary en destDictionary (si la clave ya existe, se sobrescribe)
Este es un truco y no debe utilizarse en ningún código de producción.
fuente
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
? Si no está en el código de producción, ¿dónde y por qué debería usar esto?Inspirado por Jon Skeet, he ampliado su solución con lo siguiente:
Método de extensión:
Cliente:
. . .
fuente
MoreLinq tiene
IEnumerable<T>.ForEach
y un montón de otras extensiones útiles. Probablemente no valga la pena tomar la dependencia solo porForEach
, pero hay muchas cosas útiles allí.https://www.nuget.org/packages/morelinq/
https://github.com/morelinq/MoreLINQ
fuente
Estoy totalmente en desacuerdo con la idea de que los métodos de extensión de enlace deben estar libres de efectos secundarios (no solo porque no lo están, cualquier delegado puede realizar efectos secundarios).
Considera lo siguiente:
Lo que muestra el ejemplo es realmente un tipo de enlace tardío que permite invocar una de las muchas acciones posibles que tienen efectos secundarios en una secuencia de elementos, sin tener que escribir una construcción de interruptor grande para decodificar el valor que define la acción y traducir en su método correspondiente.
fuente
Para mantenerse fluido, uno puede usar un truco así:
fuente
Para VB.NET debes usar:
fuente
List
oIList
. Para un generalIEnumerable
, escriba el equivalente VB del método de extensión ForEach de la respuesta aceptada .Otro
ForEach
ejemplofuente