2010-10-23 18 views
13

Perché il ciclo foreach è di sola lettura? Voglio dire, puoi recuperare i dati ma non puoi aumentare ++ o diminuire--. Qualche ragione dietro? Sì io sono un principiante :)Perché il ciclo foreach è di sola lettura in C#

Exmaple:

int[] myArray={1,2,3}; 
foreach (int num in myArray) 
{ 
    num+=1; 
} 
+1

Cosa significa essere di sola lettura dal ciclo while? Il ciclo while è un costrutto; non è né di sola lettura né di lettura-scrittura. Potresti forse postare del codice e/o chiarire la tua domanda, per favore? Grazie. – CesarGon

+1

Penso che stia parlando della variabile di iterazione, come in foreach (Item theItem in theItemList) ... l'oggetto non può essere assegnato a. –

+0

Ha chiarito la domanda ora: sta parlando di foreach piuttosto che mentre. – CesarGon

risposta

9

Questo è dovuto al fatto foreach è pensato per iterare su un contenitore, assicurandosi che ogni elemento viene visitata una sola volta, senza cambiare il contenitore, per evitare brutte effetti collaterali.

See: foreach in MSDN

Se volevi dire perché dovrebbero modifiche a un elemento come un intero non pregiudica un contenitore di numeri interi, e questo è perché la variabile di iterazione in questo caso sarebbe un tipo di valore ed è copiato, ad esempio:

// Warning: Does not compile 
foreach (int i in ints) 
{ 
    ++i; // Would not change the int in ints 
} 

Anche se la variabile di iterazione è stato un tipo di riferimento, la cui attività ha restituito un nuovo oggetto, non sarebbe cambiare la collezione originale, si sarebbe solo essere riassegnando a questa variabile maggior parte del tempo:

// Warning: Does not compile 
foreach (MyClass ob in objs) 
{ 
    ob=ob+ob; // Reassigning to local ob, not changing the one from the original 
      // collection of objs 
} 

Il seguente esempio ha il potenziale di modificare effettivamente l'oggetto nell'insieme originale chiamando il metodo mutante:

// Warning: Does not compile 
foreach (MyClass ob in objs) 
{ 
    ob.ChangeMe(); // This could modify the object in the original collection 
} 

Per evitare confusione in relazione al valore vs tipi di riferimento e gli scenari di cui sopra (insieme ad alcune ragioni legate all'ottimizzazione), MS ha scelto di rendere la variabile di iterazione readonly.

1

foreach è progettato per visitare ogni elemento di una raccolta esattamente una volta e non utilizza un "indice di ciclo" esplicito; se si desidera un maggiore controllo del ciclo e si dispone di un indice di loop, utilizzare for.

MODIFICA: è possibile modificare gli elementi della raccolta in iterazione all'interno di un ciclo foreach. Ad esempio:

foreach(Chair ch in mychairs) 
{ 
    ch.PaintColour = Colour.Green; //this alters the chair object *in* the collection. 
} 

Tuttavia, non è possibile aggiungere o rimuovere elementi alla/dalla raccolta.

+0

In realtà, non è possibile modificare neanche un campo/proprietà dell'oggetto a cui fa riferimento la variabile di iterazione. –

+0

@ Michael: Il codice che ho postato funziona OK per me. Sto usando .NET 3.5 e Visual Studio 2008. – CesarGon

7

Poiché l'elemento corrente viene restituito dal valore (cioè copiato). E la modifica della copia è inutile. Se si tratta di un tipo di riferimento, è possibile modificare il contenuto di tale oggetto, ma non sostituire il riferimento.

Forse dovresti leggere la documentazione di IEnumerable<T> e IEnumerator<T>. Questo dovrebbe renderlo più chiaro. Il bit più importante è che IEnumerable<T> ha una proprietà Current di tipo T. E questa proprietà ha solo un getter, ma nessun setter.

Ma cosa succederebbe se avesse un setter?

  • Sarebbe funzionare bene con array e liste
  • non funzionerebbe bene con contenitori complessi come hashtables, elenco ordinato perché il cambiamento provoca grandi cambiamenti nel contenitore (per esempio un riordino), e quindi invalida l'iteratore. (La maggior parte delle collezioni invalidano gli iteratori se vengono modificati per evitare uno stato incoerente negli iteratori.
  • In LINQ non ha alcun senso. Ad esempio con select(x=>f(x)) i valori sono risultati di una funzione e non è associata alcuna memoria permanente.
  • Con iteratori scritto con l'yield return sintassi che non ha senso né
+0

"E la modifica della copia è inutile." Cosa succede se voglio fare qualcosa come sommare il quadrato di tutti i numeri in una lista? Può essere fatto con la restrizione in sola lettura, ma è spesso utile modificare una copia. – raylu

Problemi correlati