Variables locales avec des délégués
Question
Cette
//The constructor
public Page_Index() {
//create a local value
string currentValue = "This is the FIRST value";
//use the local variable in a delegate that fires later
this.Load += delegate(object sender, EventArgs e) {
Response.Write(currentValue);
};
//change it again
currentValue = "This is the MODIFIED value";
}
La valeur en sortie est la deuxième valeur "Modifié" . Quelle partie de la magie du compilateur fait ce travail? Est-ce aussi simple que de garder une trace de la valeur sur le tas et de la récupérer ultérieurement?
[Éditer]: En fonction de certains commentaires, en modifiant la phrase d'origine en ...
La solution
currentValue n'est plus une variable locale: c'est une variable capturée . Cela compile quelque chose comme:
class Foo {
public string currentValue; // yes, it is a field
public void SomeMethod(object sender, EventArgs e) {
Response.Write(currentValue);
}
}
...
public Page_Index() {
Foo foo = new Foo();
foo.currentValue = "This is the FIRST value";
this.Load += foo.SomeMethod;
foo.currentValue = "This is the MODIFIED value";
}
Jon Skeet a une très bonne rédaction de ceci dans C # en profondeur , et un document séparé ( pas aussi détaillée) discussion ici .
Notez que la variable currentValue est maintenant sur le tas, pas sur la pile - cela a de nombreuses implications, sans oublier qu'elle peut maintenant être utilisée par différents appelants.
Cela diffère de java: en java, la valeur d'une variable est capturée. En C #, la variable elle-même est capturée.
Autres conseils
Je suppose que plus la question que je pose est que comment ça marche avec une variable locale [Modification MG: "Ack - ignore this ..." a été ajouté ensuite]
C'est le point; ce n'est vraiment pas une variable locale, du moins pas en ce qui concerne notre façon de penser (sur la pile, etc.). Cela ressemble à un, mais ça ne l’est pas.
Et pour info, il ne s'agit pas de "bonnes pratiques". - les méthodes anonymes et les variables capturées sont en fait un outil incroyablement puissant, en particulier lorsque vous travaillez avec des événements. N'hésitez pas à les utiliser, mais si vous suivez cette voie, je vous conseillerais de prendre le livre de Jon pour vous assurer de bien comprendre ce qui se passe réellement.
Vous devez capturer la valeur de la variable dans la clôture / le délégué, sinon elle peut être modifiée, comme vous l'avez vu.
Affectez currentValue à une variable locale (interne) au délégué.