2009-10-23 20 views
7

que tiene el código (C#):actualización Struct en bucle foreach en C#

using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    public struct Thing 
    { 
     public string Name; 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Thing> things = new List<Thing>(); 
      foreach (Thing t in things) // for each file 
      { 
       t.Name = "xxx"; 
      } 
     } 
    } 
} 

No va a compilar.
El error es:

Cannot modify members of 't' because it is a 'foreach iteration variable' 

Si cambio Thing a un class en lugar de un struct, sin embargo, que se compila.

Por favor alguien puede explicar lo que está pasando?

+0

Pregunta relacionada http://stackoverflow.com/questions/1538301/c-does-foreach-iterate-by-reference/1538316#1538316 –

+0

Gracias por el enlace, Brian. –

Respuesta

9

Más o menos lo que dice, el compilador no le permitirá cambiar (partes de) la varilla de bucle en un foreach.

Utilice simplemente:

for(int i = 0; i < things.Count; i+= 1) // for each file 
{ 
    things[i].Name = "xxx"; 
} 

y funciona cuando Thing es una clase porque entonces su var bucle es una referencia, y sólo realizar cambios en el objeto de referencia, no a la propia referencia.

+0

¡Exactamente lo que estaba buscando! gracias, Henk :) –

7

Una estructura no es un tipo de referencia, sino un tipo de valor.

Si desea tener un class en lugar de un struct para Thing, el bucle foreach crearía una variable de referencia para usted, que apunte al elemento correcto en que la lista. Pero dado que es un tipo de valor, solo opera en una copia de su Thing, que en este caso es la variable de iteración.

+0

Sí, es relevante. Como es un tipo de valor, la estructura completa es la variable de bucle y, por lo tanto, no se puede modificar ninguna parte de ella. –

+0

Gracias por explicarnos la diferencia, Johannes. Muy apreciado. +1 –

1

Una sintaxis alternativa que prefiero @ solución de Henk es esto.

DateTime[] dates = new DateTime[10]; 

foreach(int index in Enumerable.Range(0, dates.Length)) 
{ 
    ref DateTime date = ref dates[index]; 

    // Do stuff with date. 
    // ... 
} 

Si usted está haciendo una cantidad razonable de trabajo en el bucle y luego no tener que repetir la indexación en todas partes es más fácil en el ojo de la OMI.

P.S. DateTime es realmente un ejemplo realmente pobre, ya que no tiene ninguna propiedad que pueda establecer, pero obtiene la imagen.