Je répondais à une question sur la possibilité que des fermetures prolongent (légitimement) la durée de vie des objets lorsque je suis tombé sur un code-gen extrêmement curieux de la part du compilateur C # (4.0 si cela compte).
Le repro le plus court que je puisse trouver est le suivant:
- Créez un lambda qui capture un local tout en appelant une méthode statique du type conteneur.
- Attribuez la référence de délégué générée à un champ d' instance de l'objet conteneur.
Résultat: le compilateur crée un objet de fermeture qui fait référence à l'objet qui a créé le lambda, quand il n'a aucune raison de le faire - la cible `` interne '' du délégué est une méthode statique , et les membres de l'instance de l'objet de création lambda n'ont pas besoin être (et ne pas) touché lorsque le délégué est exécuté. En fait, le compilateur agit comme le programmeur a capturé this
sans raison.
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Le code généré à partir d'une version de version (décompilé en C # `` plus simple '') ressemble à ceci:
public void InstanceMethod()
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.<>4__this = this; // What's this doing here?
CS$<>8__locals2.capturedVariable = Math.Pow(42.0, 1.0);
this._field = new Action(CS$<>8__locals2.<InstanceMethod>b__0);
}
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public Foo <>4__this; // Never read, only written to.
public double capturedVariable;
// Methods
public void <InstanceMethod>b__0()
{
Foo.StaticMethod(this.capturedVariable);
}
}
Observez que le <>4__this
champ de l'objet de fermeture est rempli avec une référence d'objet mais n'est jamais lu (il n'y a aucune raison).
Alors qu'est-ce qui se passe ici? La spécification de la langue le permet-elle? Est-ce un bogue / bizarrerie du compilateur ou y a-t-il une bonne raison (qui me manque clairement) pour que la fermeture fasse référence à l'objet? Cela me rend anxieux parce que cela ressemble à une recette pour les programmeurs heureux de la fermeture (comme moi) d'introduire involontairement d'étranges fuites de mémoire (imaginez si le délégué était utilisé comme gestionnaire d'événements) dans les programmes.
this
.Réponses:
Cela ressemble à un bug. Merci de l'avoir porté à mon attention. Je vais l'examiner. Il est possible qu'il ait déjà été trouvé et corrigé.
la source
Cela semble être un bug ou inutile:
Je lance votre exemple en langage IL:
Exemple 2:
en cl: (Remarque !! maintenant cette référence a disparu!)
Exemple 3:
en IL: (Ce pointeur est de retour)
Et dans les trois cas, la méthode-b__0 () - a la même apparence:
Et dans les 3 cas, il y a une référence à une méthode statique, donc cela la rend plus étrange. Donc, après cette petite analyse, je dirai que c'est un bug / pour rien de bon. !
la source
Foo.InstanceMethod
est rendu statique, cela supprimerait-il également la référence? Je serais reconnaissant de savoir.Foo.InstanceMethod
étaient également statiques, il n'y aurait aucune instance en vue, et donc aucun moyen dethis
capturer quelque sorte que ce soit par la fermeture.