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
.Antworten:
Das sieht sicher nach einem Bug aus. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben. Ich werde es untersuchen. Möglicherweise wurde es bereits gefunden und behoben.
quelle
Es scheint ein Fehler oder unnötig zu sein:
Ich führe dich beispielhaft in IL lang:
Beispiel 2:
in cl: (Hinweis !! jetzt ist diese Referenz weg!)
Beispiel 3:
in IL: (Dieser Zeiger ist zurück)
Und in allen drei Fällen sieht die Methode-b__0 () gleich aus:
In allen drei Fällen wird auf eine statische Methode verwiesen, wodurch sie merkwürdiger wird. Also nach dieser kleinen Analyse werde ich sagen, es ist ein Fehler / für nichts Gutes. !
quelle
Foo.InstanceMethod
statisch gemacht wird. Würde dies auch die Referenz entfernen? Ich wäre dankbar zu wissen.Foo.InstanceMethod
es auch statisch wäre, wäre keine Instanz in Sicht und daher keine Möglichkeit, irgendeine Art vonthis
Schließung zu erfassen.