Question

Je répondais à un question à propos de la possibilité de fermetures (légitimement) étendant la vie des objets lorsque j'en ai rencontré extrêmement Curious Code-Gen de la partie du compilateur C # (4.0 si cela compte).

Le repro le plus court que je peux trouver est le suivant:

  1. Créez un lambda qui capture un local tout en appelant un statique Méthode du type contenu.
  2. Attribuez la référence du délégué généré à un exemple champ de l'objet contenant.

Résultat: le compilateur crée un objet de fermeture qui fait référence à l'objet qui a créé le lambda, lorsqu'il n'a aucune raison de - la cible `` intérieure '' du délégué est un statique Méthode, et les membres de l'instance de Lambda-Creating-Object n'ont pas besoin d'être (et ne sont pas) touchés lorsque le délégué est exécuté. En effet, le compilateur agit comme le programmeur 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 «simple» C #) 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);
    }
}

Observe ceci <>4__this Le champ de l'objet de fermeture est rempli d'une référence d'objet mais n'est jamais lu (il n'y a aucune raison).

Alors, que se passe-t-il ici? La spécification du langage le permet-il? S'agit-il d'un bug / bizarrerie du compilateur ou y a-t-il une bonne raison (qui me manque clairement) pour que la fermeture fait référence à l'objet? Cela me rend anxieux parce que cela ressemble à une recette pour les programmeurs de fermeture (comme moi) pour introduire involontairement des fuites de mémoire étranges (imaginez si le délégué a été utilisé comme un mainteur d'événements) dans des programmes.

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top