Mise à jour: pour voir ce qui se passe réellement sans avoir à recourir à l'IL: Using reflector to understand anonymous methods and captured variables
Lorsque vous utilisez:
public Bar CreateBar()
{
return new Bar(x,() => y);
}
Vous implicitement this.y
qui signifie; donc en termes de délégué, c'est la référence à Foo
qui est inclus. En tant que tel, l'instance de Bar
(via le délégué) conserve l'intégralité de Foo
en vie (non récupérée) jusqu'à ce que le Bar
soit disponible pour la collecte.
En particulier, il n'est pas nécessaire (dans ce cas) que le compilateur génère une classe supplémentaire pour gérer les variables capturées; la seule chose requise est l'instance Foo
, donc une méthode peut être générée sur Foo
. Cela serait plus complexe si le délégué impliquait des variables locales (autres que this
).
En termes de sérialisation ... eh bien, la première chose que je dirais, c'est que sérialiser les délégués est une très très mauvaise idée. Cependant, BinaryFormatter
sera délégués à pied, et vous pouvez (en théorie) finissent avec une sérialisé Bar
, un sérialisé Foo
, et un délégué sérialisé pour les relier - mais seulement si vous marquez Foo
comme [Serializable]
. Mais je souligne - c'est mauvaise idée. J'utilise rarement BinaryFormatter
(pour une variété de raisons), mais une question commune que je vois par les gens qui l'utilisent est "pourquoi essaie-t-il de sérialiser (un certain type aléatoire)". Habituellement, la réponse est "vous publiez un événement, et il essaie de sérialiser l'abonné", auquel cas le correctif le plus courant serait de marquer le champ de l'événement comme [NonSerialized]
.
Plutôt que de regarder IL; une autre façon d'étudier ceci est d'utiliser un réflecteur en mode .NET 1.0 (c'est-à-dire sans échange de données dans des méthodes anonymes); alors vous pouvez voir:
public Bar CreateBar()
{
return new Bar(this.x, new Func<int>(this.<CreateBar>b__0));
}
[CompilerGenerated]
private int <CreateBar>b__0()
{
return this.y;
}
Comme vous pouvez le voir; la chose transmise à Bar
est un délégué à une méthode cachée (appelée <CreateBar>b__0()
) sur l'instance en cours (this
). Donc, il est l'instance à l'actuelle Foo
qui est transmise au Bar
.
Dans la section 6.5.3 du langage de programmation C# (3ème édition), il y a un exemple très similaire à ce cas et il est manipulé comme Marc l'a expliqué par une méthode d'instance générée par le compilateur sur Foo. –
Réponse fantastique Marc! Merci! –