Pourquoi une boucle foreach
est-elle une boucle en lecture seule? Quelles sont les raisons pour cela?Pourquoi est-ce que je ne peux pas modifier la variable de boucle dans un foreach?
Répondre
Je ne sais pas exactement ce que vous entendez par une « boucle en lecture seule » mais je devine que vous voulez savoir pourquoi cela ne compile pas:
int[] ints = { 1, 2, 3 };
foreach (int x in ints)
{
x = 4;
}
Le code ci-dessus donnera les éléments suivants erreur de compilation:
Cannot assign to 'x' because it is a 'foreach iteration variable'
Pourquoi cela est-il interdit? Essayer de l'assigner ne ferait probablement pas ce que vous voulez - cela ne modifierait pas le contenu de la collection originale. C'est parce que la variable x n'est pas une référence aux éléments de la liste - c'est une copie. Pour éviter que les gens écrivent du code bogué, le compilateur n'autorise pas cela.
+1. C'est comme dire 'Foo x = new Foo(); Foo y = x; y = new Foo(); 'Ajuster' y' à 'new Foo()' ne fait rien à 'x'. De même, avoir 'foo' comme variable de boucle et dire' foo = new Foo(); '(si vous le pouvez **) ne fait rien pour' Foo' dans la collection. –
C'est (la partie de copie) pas vrai pour le type de référence, alors x contiendrait une référence à l'objet dans le IEnumerable –
@Rune FS: Dans le cas des types de référence c'est une * copie * de la référence. Même dans ce cas, il ne ferait probablement pas ce que vous vouliez si vous pouviez l'assigner. –
Je suppose que c'est ainsi que l'itérateur parcourt la liste.
Supposons que vous avez une liste triée:
Alaska
Nebraska
Ohio
Au milieu de
foreach(var s in States)
{
}
Vous faites un States.Add ("Missouri")
Comment traitez-vous cela? Sautez-vous alors au Missouri même si vous avez déjà dépassé cet indice.
Le contrat de Microsoft pour iEnumerable dit qu'un iEnumerable ne devrait pas fournir de moyen de mettre à jour la collection sans provoquer une exception quand énumérer l'élément suivant. Si j'avais mes connaissances, un enquêteur dans votre scénario serait libre d'inclure ou non le Mississippi, mais il faudrait soit énumérer exactement une fois tous les éléments qui existaient tout au long de l'énumération, soit lancer une exception s'il ne pouvait pas le faire. – supercat
Si, par cela, vous voulez dire:
Why shouldn't I modify the collection that's being
foreach
'd over?
Il n'y a pas de caution que les articles que vous obtenez sortira dans l'ordre donné, et que l'ajout d'un élément, ou la suppression d'un article ne sera pas provoque la modification de l'ordre des éléments de la collection, ou même l'énumérateur devient invalide.
Imaginez si vous exécutiez le code suivant:
var items = GetListOfTOfSomething(); // Returns 10 items
int i = 0;
foreach(vat item in items)
{
i++;
if (i == 5)
{
items.Remove(item);
}
}
Dès que vous appuyez sur la boucle où i est 6 (à savoir après l'élément est supprimé) tout peut arriver. L'énumérateur a peut-être été invalidé parce que vous avez supprimé un élément, tout pourrait avoir été "mélangé par un" dans la collection sous-jacente, provoquant la suppression d'un élément, ce qui signifie que vous en "sautez" un.
Si vous vouliez dire « pourquoi je ne peux pas changer la valeur qui est fournie à chaque itération », puis, si la collection vous travaillez avec contient value types, les modifications apportées ne seront pas conservés comme il est un valeur avec laquelle vous travaillez, plutôt qu'une référence .
foreach
fonctionne avec tout ce qui implémente l'interface IEnumerable
. Afin d'éviter les problèmes de synchronisation, l'énumérable ne doit jamais être modifié lors de son itération. Les problèmes surviennent si vous ajoutez ou supprimez des éléments d'un autre thread pendant l'itération: en fonction de l'endroit où vous vous trouvez, vous risquez de manquer un élément ou d'appliquer votre code à un élément supplémentaire. Ceci est détecté par le runtime (dans certains cas ou tous ???) Et lève une exception:
System.InvalidOperationException was unhandled
Message="Collection was modified; enumeration operation may not execute."
foreach
cherche à obtenir point suivant chaque itération qui peut causer des problèmes si vous modifiez d'un autre fil en même temps.
La commande foreach
utilise l'interface IEnumerable
pour effectuer une boucle dans la collection. L'interface n'a défini que des méthodes pour parcourir une collection et obtenir l'élément en cours, il n'existe aucune méthode pour mettre à jour la collection. Comme l'interface ne définit que les méthodes minimales requises pour lire le collecton dans un sens, l'interface peut être mise en œuvre par un large éventail de collections.
Étant donné que vous n'accédez qu'à un seul élément à la fois, la totalité de la collection n'a pas besoin d'exister en même temps. Ceci est par exemple utilisé par les expressions LINQ, où il crée le résultat à la volée au fur et à mesure que vous le lisez, au lieu de créer d'abord le résultat entier, puis de le parcourir en boucle.
Je ne sais pas ce que vous voulez dire en lecture seule, mais je suppose que la compréhension de ce que la boucle foreach est sous le capot aidera. Il est du sucre syntaxique et pourrait aussi être écrit quelque chose comme ceci:
IEnumerator enumerator = list.GetEnumerator();
while(enumerator.MoveNext())
{
T element = enumerator.Current;
//body goes here
}
Si vous changez la collection (liste), il devient difficile impossible de savoir comment traiter l'itération. Assigner à l'élément (dans la version de foreach) pourrait être vu comme essayant d'assigner à l'énumérateur. Courant qui est en lecture seule ou essayant de changer la valeur du local tenant une référence à l'énumérateur.Current auquel cas vous pourriez aussi bien présenter un local, car il n'a plus rien à voir avec la liste énumérée.
- 1. foreach ne pas initialiser la variable de boucle
- 2. Alors que boucle dans foreach boucle ne boucle pas correctement
- 3. Pourquoi je ne peux pas lancer une boucle en Javascript?
- 4. Pourquoi je ne peux pas instancier cette variable?
- 5. Pourquoi ne puis-je pas foreach (var Item dans DataTable.Rows)?
- 6. Pourquoi ne pas utiliser ma boucle conteneur foreach?
- 7. Pourquoi ne reçois-je pas d'avertissement lorsque je redéclare la variable de contrôle Per foreach?
- 8. je ne peux pas obtenir variable dans la fonction
- 9. Pourquoi je ne peux pas INSERT INTO?
- 10. Pourquoi je ne peux pas appeler packagename.modulename.foo()?
- 11. Pourquoi est-ce que je ne peux pas sortir un chemin dans la console des rails?
- 12. Pourquoi je ne peux pas l'utiliser?
- 13. Existe-t-il un moyen de modifier la variable de boucle foreach?
- 14. Pourquoi est-ce que je ne peux pas référencer une variable globale directement en PHP?
- 15. Un bug particulier que je ne peux pas sembler trouver
- 16. Je ne peux pas ouvrir le nom de fichier variable
- 17. Pourquoi je ne peux pas dessiner dans une boucle? (L'utilisation UIView dans l'iPhone)
- 18. Utilisation de la variable itératrice de la boucle foreach dans une expression lambda - pourquoi échoue?
- 19. Pourquoi je ne peux pas ajouter un JPanel à JFrame?
- 20. Pourquoi en C#, dans la zone de liste déroulante de contrôle, je ne peux pas modifier la propriété SelectedItem?
- 21. Pourquoi est-ce que je ne peux pas piéger un clic de souris dans IE?
- 22. Comportement de la Viewbox que je ne peux pas comprendre
- 23. Pourquoi je ne peux pas sortir de ce bloc Ruby?
- 24. android pourquoi je ne peux pas récupérer un bitmap compressé?
- 25. Je peux ajouter mon webpart personnalisé, mais je ne peux pas modifier un webpart sur la page
- 26. Pourquoi je ne peux pas lier + dans clojure?
- 27. Pourquoi est-ce que je ne peux pas centrer un <td> dans IE7?
- 28. Pourquoi est-ce que je ne peux pas mettre une constante dans un CGRectMake?
- 29. modifier le tableau initial à l'intérieur de la boucle foreach?
- 30. Pourquoi est-ce que je ne peux pas stocker XML dans la valeur ASP.NET ListBox?
Je ne suis pas sûr de ce que vous entendez par une boucle en lecture seule. Faites-vous référence au fait que vous ne devriez pas modifier la variable d'itération de la boucle? I.e pour chaque article dans myitems item.property = quelque chose suivant – Tommy
Je ne sais pas comment appliquer le concept de lecture seule à une boucle for. Ou voulez-vous dire pourquoi ils disent que c'est en lecture seule? – helios
Si vous parlez de l'énumération - oui! Vous ne pouvez pas modifier l'énumération que vous parcourez. –