Cet objet-life-time-extending-cllosure est-il un bug du compilateur C #?
-
29-10-2019 - |
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:
- Créez un lambda qui capture un local tout en appelant un statique Méthode du type contenu.
- 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