2009-07-21 22 views

Respuesta

33

Suponiendo que newsplit es un IEnumerable<string>, que quiere:

newsplit = newsplit.Select(x => "WW"); 

El código que tiene actualmente es equivalente a la siguiente:

foreach(string x in newsplit.ToList()) { 
    AssignmentAction(x); 
} 

... 

public static void AssignmentAction(string x) { 
    x = "WW"; 
} 

Este método no modificarán debido a la x semántica de paso a paso de C# y la inmutabilidad de las cadenas.

+0

Es una matriz de cadenas o en mi caso una lista IEnumerable como yo no creo que es? – Jon

+0

@Jon: arrays y List son compatibles con la interfaz IEnumerable –

+1

No creo que Select() sea lo que Jon quiere, parece que quiere modificar el IEnumerable. Seleccionar solo le dará los elementos que ya son "WW" – AgileJon

0

Se debe a que la expresión LINQ está creando Anonymous Types, y estos son de solo lectura. No pueden ser asignados a. Además, en un estándar para cada ciclo no puede asignarlo a una colección que se está enumerando. Pruebe:

foreach (var item in newsplit) 
    { 
     item = "this won't work"; 
    } 
+0

No hay ningún tipo anónimo creado en la expresión ForEach dada. El parámetro es un delegado, que se aplica a cada elemento en la iteración; y por supuesto, no funcionará por la razón que das. –

+0

Tienes razón, por supuesto, ¡no estoy seguro de lo que estaba pensando! Pero la segunda parte, sobre colecciones que son inmutables cuando se repiten, vale la pena señalar. Gracias. –

2

ForEach le permitirá manipular los elementos de IEnumerable, pero no cambia la referencia del elemento.

es decir, esto sentaría un Foo propiedad de cada elemento en el IEnumerable a la cadena "WW":

newsplit.ToList().ForEach(x => x.Foo = "WW"); 

Sin embargo, usted no será capaz de modificar los valores dentro de la propia IEnumerable.

+0

Al menos en VB.Net solo pude asignar la propiedad del elemento dentro de ForEach si el ForEach multilínea, el Linq ForEach no se asignaría por referencia. – Brent

17

Otras respuestas explican por qué su código actual no funciona. Aquí es un método de extensión que solucionarlo:

// Must be in a static non-nested class 
public static void ModifyEach<T>(this IList<T> source, 
           Func<T,T> projection) 
{ 
    for (int i = 0; i < source.Count; i++) 
    { 
     source[i] = projection(source[i]); 
    } 
} 

A continuación, utilice la siguiente manera:

newsplit.ModifyEach(x => "WW"); 

que funcionará con cualquier aplicación de IList<T> tales como matrices y List<T>. Si necesita que funcione con un IEnumerable<T> arbitrario, entonces tiene un problema, ya que la secuencia en sí misma puede no ser mutable.

usando Select() es un enfoque más funcional, por supuesto, pero a veces la mutación de una colección existente es digno de hacer ...

+1

@Jon: Creo que se refería a newsplit.ToList(). ¿ModifyEach (x => "WW") en su segundo bloque de código? – jason

+2

@Jason: Casi ... pero si llama a ToList() pero no mantiene una referencia a esa nueva lista, las modificaciones no se conservarán. En particular, * no * modificaría la colección original. He editado la respuesta para el uso previsto. –

+0

@Jon: De acuerdo. Gracias por aclararlo. – jason

Cuestiones relacionadas