2010-10-23 13 views
13

Dlaczego pętla foreach jest tylko do odczytu? Chodzi mi o to, że możesz pobrać dane, ale nie możesz ich zwiększyć ani zmniejszyć. Jakiś powód za tym? Tak, jestem początkujący :)Dlaczego pętla foreach jest tylko do odczytu w C#

Exmaple:

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

Co masz na myśli jest tylko do odczytu przez pętli while? Pętla while jest konstrukcją; nie jest on ani do odczytu, ani do odczytu i zapisu. Czy możesz po prostu napisać jakiś kod i/lub wyjaśnić swoje pytanie? Dzięki. – CesarGon

+1

Myślę, że on mówi o zmiennej iteracji, jak w foreach (pozycja theItem w theItemList) ... theItem nie można przypisać. –

+0

Teraz wyjaśnił pytanie: mówi o foreach, a nie czasie. – CesarGon

Odpowiedz

9

To dlatego foreach jest przeznaczona do iteracyjnego pojemnik, upewniając się, każdy element jest dokładnie raz odwiedził, bez zmiany pojemnika, aby uniknąć nieprzyjemnych skutki uboczne.

Patrz: foreach in MSDN

Jeśli rozumie dlaczego zmiany elementu jak liczba całkowita nie wpływa pojemnik z liczb całkowitych, a to dlatego, że zmienna iteracji w tym przypadku będzie to typ wartości i jest kopiowany, np:

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

Nawet jeśli zmienna iteracji był typem odniesienia, którego operacje powrócił nowy obiekt, nie byłoby zmieniając oryginalną kolekcję, to po prostu być realokacja do tej zmiennej przez większość czasu:

// 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 
} 

Poniższy przykład ma potencjał, aby właściwie modyfikacji obiektu w oryginalnej kolekcji wywołując mutacjom metody:

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

Aby uniknąć nieporozumień w odniesieniu do wartości vs typów odniesienia oraz scenariusze wspomniano powyżej (wraz z niektórymi przyczynami związanymi z optymalizacją), firma MS zdecydowała się wprowadzić zmienną iteracji readonly.

1

foreach jest zaprojektowany do odwiedzania każdej pozycji w kolekcji dokładnie jeden raz i nie używa wyraźnego "indeksu pętli"; jeśli chcesz mieć większą kontrolę nad pętlą i mieć indeks pętli, użyj for.

EDYCJA: Możesz zmienić elementy w kolekcji, która jest iterowana wewnątrz pętli foreach. Na przykład:

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

Nie można jednak dodawać ani usuwać elementów do/z kolekcji.

+0

W rzeczywistości nie można modyfikować pola/właściwości obiektu, do którego odnosi się zmienna iteracji. –

+0

@Michael: Kod, który wysłałem, działa dobrze dla mnie. Korzystam z .NET 3.5 i Visual Studio 2008. – CesarGon

7

Ponieważ bieżący element jest zwracany przez wartość (tj. Kopiowany). I modyfikowanie kopii jest bezużyteczne. Jeśli jest to typ odniesienia, można zmodyfikować zawartość tego obiektu, ale nie może zastąpić odniesienia.

Być może powinieneś przeczytać dokumentację IEnumerable<T> i IEnumerator<T>. To powinno uczynić go jaśniejszym. Najważniejszym jest to, że IEnumerable<T> ma właściwość Current typu T. A ta właściwość ma tylko gettera, ale nie ma setera.

Ale co by się stało, gdyby miał setera?

  • Byłoby dobrze pracować z tablicami i listy
  • Nie byłoby dobrze pracować ze złożonymi pojemnikach jak hashtables, uporządkowane listy, ponieważ zmiana powoduje większych zmian w pojemniku (na przykład zmiana kolejności), a tym samym unieważnia iterator. (Większość kolekcji unieważnia iteratory, jeśli zostaną zmodyfikowane, aby uniknąć niespójnego stanu w iteratorach.)
  • W LINQ to nie ma żadnego sensu. Na przykład z wartościami select(x=>f(x)) wartości są wynikami funkcji i nie są powiązane z żadnym stałym magazynem.
  • Z iteratorów napisane ze składnią yield return to nie ma sensu, albo
+0

"I modyfikowanie kopii jest bezużyteczne." Co jeśli chcę zrobić coś takiego, jak zsumować kwadrat wszystkich liczb na liście? Można to zrobić za pomocą ograniczenia tylko do odczytu, ale często jest przydatne modyfikowanie kopii. – raylu

Powiązane problemy