J'ai été de répondre à une question sur la possibilité de fermetures (légitimement) s'étendant au-objet-durée de vie quand j'ai couru dans certains extrêmement curieux de code-gen de la part du compilateur C# (4.0 si ce qui compte).
Le plus court repro je peux trouver est la suivante:
- Créer un lambda qui capture un local en appelant une statique méthode du type contenant.
- Attribuer le générés délégué référence à une occurrence de champ de l'objet contenant.
Résultat: Le compilateur crée une fermeture-objet qui fait référence à l'objet qui a créé le lambda, quand il n'a aucune raison de le faire, le "intérieure" de la cible du délégué est un statique de la méthode, et le lambda-la création de l'objet les membres de l'instance n'a pas besoin d'être (et ne sont pas touchées lorsque le délégué est exécutée. Effectivement, le compilateur est d'agir 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 build (décompilé de "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);
}
}
Observer qu' <>4__this
domaine de la fermeture de l'objet est rempli avec un objet de référence, mais n'est jamais de lire (il n'y a pas de raison).
Alors que ce passe ici? Le langage de spécification de permettre à pour cela? Est-ce un bug du compilateur / bizarrerie ou est-il une bonne raison (que je suis clairement en manque) pour la fermeture de référence de l'objet? Ce qui me rend anxieux parce que cela ressemble à une recette pour la fermeture-heureux les programmeurs (comme moi) à involontairement introduire étrange mémoire-fuites (imaginez si le délégué ont été utilisés comme un gestionnaire d'événements) dans les programmes.