9
votes

Pourquoi ne puis-je pas modifier la variable de boucle dans un forach?

Pourquoi un foreach une boucle en lecture seule? Quelles raisons sont là pour cela?


6 commentaires

Je ne suis pas sûr de ce que vous entendez par une boucle réadonnée. Faites-vous référence au fait que vous ne devez pas modifier la variable d'itération de la boucle? I.e pour chaque article dans myITEMS item.property = quelque chose suivant


Je ne sais pas comment appliquer le concept en lecture seule à une boucle. Ou voulez-vous dire pourquoi ils disent que c'est en lecture seule?


Si vous parlez de l'énumération - oui! Vous ne pouvez pas changer l'énumération que vous bouclez.


oui @tommy c'est ce que je voulais dire


Dupliquer de Stackoverflow.com/Questtions/776430/...


Question en double: Stackoverflow.com/Questtions/3549750/...


6 Réponses :


22
votes

Je ne sais pas exactement ce que vous entendez par une "boucle réadonn", mais je suppose que vous voulez savoir pourquoi cela ne compile pas: xxx pré>

Le code ci-dessus sera Donnez l'erreur de compilation suivante: P>

Cannot assign to 'x' because it is a 'foreach iteration variable'


7 commentaires

+1. Il est similaire à dire foo x = nouveau foo (); Foo y = x; y = nouveau foo (); paramètre y à nouveau foo () ne fait rien à x . De même, avoir FOO comme variable de boucle et disant foo = nouveau foo (); (si vous pouviez **) ne fait rien au foo dans la collection.


C'est (la partie de copie) non true pour le type de référence, alors x déterrerait une référence à l'objet dans l'iNeuble


@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, cela ne ferait probablement pas ce que vous vouliez si vous pouviez vous assigner.


@Rune, x contiendrait l'adresse de l'objet. Dire x = nouvelle barre () créerait une nouvelle barre ou stocker son adresse dans x . L'objet dans la collection ne serait pas modifié. Ce n'est pas différent de transmettre un paramètre dans une fonction, puis de modifier le paramètre. La variable sur le site d'appel n'est pas affectée (sauf si un modificateur de code ou ref est utilisé dans la signature de la méthode).


@mark Je suis avec vous sur vous n'abandonnez pas à la "X", mais cela fait beaucoup de différence lorsque vous affectez une propriété / un champ de 'x' s'il s'agit d'un type de valeur ou d'un type de référence. Dans le premier cas, le changement est perdu lorsque la boucle se termine dans la seconde, elle durer jusqu'à modification à nouveau ou que l'objet est collecté.


@Anthony, il semble que vous avez mal compris moi et que c'est une référence à l'objet que la variable détient cette pourrait être mise en œuvre comme un pointeur, mais qui n'est pas requis par les spécifications


@Rune FS: Exactement, c'est l'idée qui m'a fait poser cette question



5
votes

Je suppose que c'est comment l'itérateur se déplace dans la liste.

Dites que vous avez une liste triée: p> xxx pré>

au milieu de p>

foreach(var s in States)
{
}


1 commentaires

Le contrat de Microsoft pour iEnumerable dit qu'un iEnumerable ne devrait fournir aucun moyen de mettre à jour la collection sans que l'exception soit lancée lors de l'énumération de l'élément suivant. Si j'avais mes druthers, un énumérateur de votre scénario serait libre d'inclure ou non d'inclure le Mississippi, mais il serait nécessaire d'énumérer exactement une fois tous les éléments existants tout au-delà de l'énumération, ou lancez une exception s'il ne pouvait pas faire cela.



3
votes

Si, par ceci, vous voulez dire:

Pourquoi ne devrais-je pas modifier la collection qui est en train d'être foreach d sur?

Il n'y a pas de caution que les éléments que vous obtenez sortent dans une commande donnée et que l'ajout d'un article ou que la suppression d'un article ne provoque pas l'ordre des éléments de la collection de modifier ou Même l'énumérateur à devenir invalide.

Imaginez si vous avez exécuté le code suivant: xxx

dès que vous avez frappé la boucle où je suis 6 (c.-à-d. Une fois que l'article est supprimé) tout pourrait arriver . L'énumérateur a peut-être été invalidée en raison de la suppression d'un article, tout aurait peut-être «mélanger par un» dans la collection sous-jacente provoquant un élément de prendre la place du retiré, ce qui signifie que vous «sautez». < p> Si vous vouliez dire "Pourquoi ne pouvez-je pas changer la valeur fournie sur chaque itération" alors, si la collecte que vous utilisez contient Types de valeur , les modifications que vous apportez ne seront pas conservées car c'est une valeur que vous «Nécessez-vous avec, plutôt que de référence .


0 commentaires

0
votes

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é tout en itération de celui-ci.

Les problèmes naissent si vous ajoutez ou supprimez des éléments dans un autre thread tout en itérant: Selon l'endroit où vous êtes, vous risquez de manquer un élément ou d'appliquer votre code à un article supplémentaire. Ceci est détecté par le temps d'exécution (dans certains cas ou tout ???) et jette une exception: xxx

foreach essaie d'obtenir un élément suivant chaque itération qui peut causer des problèmes si vous la modifiez d'un autre fil en même temps.


0 commentaires

1
votes

La commande foreach utilise l'interface iEnumerable sur la boucle de la collection. L'interface uniquement définie des méthodes définies pour passer à travers une collection et obtenir l'élément actuel, il n'y a pas de méthodes de mise à jour de la collection.

Comme l'interface définit uniquement les méthodes minimales nécessaires pour lire le collecteur dans une direction, l'interface peut être mise en œuvre par une large gamme de collections.

Comme vous n'accumulez qu'un seul élément à la fois, toute la collection n'a pas à exister en même temps. Ceci est par exemple utilisé par les expressions LINQ, où cela crée le résultat à la volée lorsque vous le lisez, au lieu de créer d'abord tout le résultat, puis de vous laisser boucler.


0 commentaires

1
votes

Je ne sais pas ce que vous entendez avec lecture seule, mais je suppose que la compréhension de ce que la boucle de foresach est sous la hotte aidera. C'est le sucre syntaxique et pourrait également être écrit quelque chose comme ceci: xxx

si vous changez de la collection (liste), il est difficile de comprendre la manière de déterminer comment traiter l'itération. L'attribution à l'élément (dans la version foreach) pourrait être visualisée comme étant d'essayer d'attribuer à Enumerator.Current, qui est en lecture seule ou en essayant de modifier la valeur de la locale détenant une référence à Enumerator.current auquel cas vous pourriez aussi bien introduire un Local vous-même parce que cela n'a plus rien à voir avec la liste énumérée.


0 commentaires