Ich beantwortete eine Frage zur Möglichkeit von Schließungen (zu Recht), die die Lebensdauer von Objekten verlängern, als ich auf einen äußerst merkwürdigen Code-Gen des C # -Compilers stieß (4.0, wenn das wichtig ist).
Der kürzeste Repro, den ich finden kann, ist der folgende:
- Erstellen Sie ein Lambda, das ein lokales erfasst, während Sie eine statische Methode des enthaltenen Typs aufrufen .
- Weisen Sie die generierte Delegatenreferenz einem Instanzfeld des enthaltenen Objekts zu.
Ergebnis: Der Compiler erstellt ein Abschlussobjekt, das auf das Objekt verweist, das das Lambda erstellt hat, wenn es keinen Grund dazu hat. Das 'innere' Ziel des Delegaten ist eine statische Methode, und die Instanzmitglieder des Lambda-Erstellungsobjekts müssen dies nicht berührt werden (und nicht), wenn der Delegat ausgeführt wird. Tatsächlich verhält sich der Compiler so, wie der Programmierer ihn this
ohne Grund erfasst hat .
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Der generierte Code aus einem Release-Build (dekompiliert in 'einfacheres' C #) sieht folgendermaßen aus:
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);
}
}
Beachten Sie, dass das <>4__this
Feld des Abschlussobjekts mit einer Objektreferenz gefüllt ist, aber niemals gelesen wird (es gibt keinen Grund).
Also, was ist hier los? Erlaubt die Sprachspezifikation dies? Ist dies ein Compiler-Fehler / eine Kuriosität oder gibt es einen guten Grund (den ich eindeutig vermisse), dass der Abschluss auf das Objekt verweist? Dies macht mich ängstlich, da dies wie ein Rezept für abschlussfreudige Programmierer (wie mich) aussieht, unabsichtlich seltsame Speicherlecks (stellen Sie sich vor, der Delegierte würde als Event-Handler verwendet) in Programme einzuführen.
this
.