2009-10-23 18 views
7

Ho questo codice (C#):Aggiornamento Struct in foreach ciclo in 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"; 
      } 
     } 
    } 
} 

Non verrà compilato.
L'errore è:

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

Se cambio Thing ad un class piuttosto che un struct, tuttavia, si compila.

Per favore qualcuno può spiegare cosa sta succedendo?

+0

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

+0

Grazie per il collegamento, Brian. –

risposta

9

Più o meno quello che dice, il compilatore non ti permetterà di cambiare (parti di) la variabile loop in un foreach.

utilizzare semplicemente:

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

e funziona quando Thing è una classe, perché allora la vostra var loop è un riferimento, e si fa solo modifiche all'oggetto di riferimento, non al riferimento stesso.

+0

Esattamente quello che stavo cercando! grazie, Henk :) –

7

Una struttura non è un tipo di riferimento ma un tipo di valore.

Se si avrebbe un class invece di un struct per Thing, il ciclo foreach creerebbe una variabile di riferimento per voi, che puntare all'elemento corretto in voi lista. Ma poiché è un tipo di valore, funziona solo su una copia del tuo Thing, che è in questo caso la variabile di iterazione.

+0

Sì, è rilevante. Poiché si tratta di un tipo di valore, l'intera struttura è la variabile di ciclo e pertanto nessuna parte di essa può essere modificata. –

+0

Grazie per aver spiegato la differenza, Johannes. Molto apprezzato. +1 –

1

Una sintassi alternativa che preferisco @ soluzione di Henk è questo.

DateTime[] dates = new DateTime[10]; 

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

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

Se stai facendo una ragionevole quantità di lavoro nel circuito poi non dover ripetere l'indicizzazione è ovunque più facile per gli occhi imo.

P.S. DateTime è in realtà un esempio davvero scarso in quanto non ha proprietà che puoi impostare, ma ottieni l'immagine.