Pourquoi ne peut-on pas attribuer un foreach variable d'itération, alors que l'on peut complètement modifier avec un accesseur?
J'étais juste curieux de savoir à ce sujet: le code suivant ne compile pas, parce que nous ne pouvons pas modifier un foreach variable d'itération:
foreach (var item in MyObjectList)
{
item = Value;
}
Mais, la suite de la compilation et de l'exécution:
foreach (var item in MyObjectList)
{
item.Value = Value;
}
Pourquoi le premier pas valide, alors que la seconde peut faire la même chose en dessous (j'ai été chercher la bonne expression anglaise pour cela, mais je ne m'en souviens pas. En vertu de la...? ^^ )
- Je pense que tu veux dire "sous le capot" - mais ce n'est pas vraiment la même chose.
- Pouvez-vous décrire comment vous 'faire de même dans votre setter?
this = value
? - Yess Sous le capot ^^. Ok, donc l'élément est en fait une référence à l'objet et non l'objet lui-même, je l'ai maintenant
- vous avez entièrement raison, j'ai oublié que les deux objets avec les mêmes valeurs pour toutes les propriétés ne veux pas dire qu'ils sont égaux
Vous devez vous connecter pour publier un commentaire.
foreach est une lecture que l'itérateur qui itère dynamiquement les classes qui implémentent l'interface IEnumerable, chaque cycle dans le foreach va appeler l'interface IEnumerable pour obtenir l'élément suivant l'élément que vous avez est en lecture seule référence, vous ne pouvez pas ré-affecter, mais simplement en appelant
item.Value
est d'y accéder et de l'affectation d'une valeur à une lecture/écriture de l'attribut mais encore la référence de l'élément en lecture seule référence.T GetEnumerator()
,bool MoveNext()
des méthodes et unT Current
de propriété (en supposant que vous souhaitez créer votre propre agent recenseur). Vous n'avez pas réellement besoin de mettre en œuvreIEnumerable
.La deuxième n'est pas du tout la même chose. Ce n'est pas la modification de la valeur de la
item
variable - c'est la modification d'une propriété de l'objet pour lequel cette valeur se réfère. Ces deux seulement être équivalent siitem
est une mutable type de valeur - dans ce cas, vous devriez changer que de toute façon, comme mutable types de valeur sont le mal. (Ils se comportent dans toutes sortes de façons dont les imprudents développeur ne peut pas attendre.)C'est la même chose comme ceci:
Voir mon l'article sur les références et les valeurs pour plus d'informations.
Vous ne pouvez pas modifier une collection alors qu'il est énuméré. Le deuxième exemple que des mises à jour une propriété de l'objet, ce qui est totalement différent.
Utiliser un
for
boucle si vous avez besoin d'ajouter/supprimer/modifier des éléments dans une collection:Si vous regardez la spécification du langage, vous pouvez voir pourquoi cela ne fonctionne pas:
Les spécifications dire qu'un foreach est élargi pour le code suivant:
Comme vous pouvez le voir l'élément courant est utilisé pour appeler la méthode MoveNext() une. Donc, si vous modifiez l'élément courant le code est perdu et ne peut pas effectuer une itération sur la collection.
Par conséquent, la modification de l'élément de quelque chose d'autre n'a aucun sens si vous voyez ce code que le compilateur est en fait la production.
v
tiendra le courant de référence de l'élément ete
détient l'itérateur de référence. Ainsi, le compilateur pourrait juste assigner ce que nous voulions ov
ete
sera toujours la tenue de l'itérateur. De cette façon foreach les variables de l'élément peut être attribué de nouvelles références, comme ils sont convertis à l'v
variable, pase
.Il serait être possible de faire
item
mutable. On pourrait changer la façon dont le code est produit, de sorte que:Est devenu équivalent à:
Et il serait alors compiler. Il ne serait toutefois pas influer sur la collecte.
Et il n'y a que le bât blesse. Le code:
A deux façons raisonnables pour un homme de penser. L'une est que
item
est juste une place de titulaire et de modification n'est pas différent à l'évolution de laitem
dans:L'autre est que le changement de point réellement changer la collecte.
Dans le premier cas, il suffit d'affecter à une autre variable, et ensuite jouer avec, donc il n'y a pas de perte. Dans ce dernier cas, c'est à la fois interdit (ou au moins, vous ne pouvez pas attendre de modifier une collection tout en évoluant à travers elle, même si elle ne ont à être appliqué par tous les agents recenseurs) et dans de nombreux cas, impossible à fournir (selon la nature de l'énumérable).
Même si l'on considère le premier cas être la "bonne" mise en œuvre, le fait qu'elle peut être raisonnablement interprétée par l'homme de deux façons différentes est une assez bonne raison pour éviter le permettant, compte tenu en particulier, nous pouvons contourner facilement que dans tous les cas.
Parce que le premier n'a pas beaucoup de sens, en fait. L'élément variable est contrôlée par l'itérateur (set à chaque itération). Vous ne devriez pas changer il suffit d'utiliser une autre variable:
Que pour le deuxième, il y a l'utilisation des cas, il n' - vous pourriez vouloir d'effectuer une itération sur une énumération de voitures et d'appel .En voiture() sur chacun d'eux, ou de définir
car.gasTank = full;
Le point est que vous ne pouvez pas modifier le collection elle-même lors de l'itération sur elle. Il est tout à fait légal et commun à modifier les objets de l'itérateur rendements.
Parce que les deux ne sont pas les mêmes. Lors de la première, vous pourriez vous attendre à modifier la valeur qui est dans la collection. Mais la façon dont
foreach
œuvres, il n'existe aucun moyen qui aurait pu être fait. Il ne peut récupérer des éléments de la collection, de ne pas les mettre.Mais une fois que vous avez l'article, c'est un objet comme les autres et vous pouvez le modifier en tout (permis) ainsi, vous pouvez.
Utiliser pour la boucle au lieu de la boucle foreach et d'attribuer de la valeur. il travaillera