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
.