Stavo rispondendo a una domanda sulla possibilità di chiusure (legittimamente) estendendo la durata degli oggetti quando ho incontrato un code-gen estremamente curioso da parte del compilatore C # (4.0 se è importante).
La riproduzione più breve che riesco a trovare è la seguente:
- Crea un lambda che acquisisce un locale mentre chiama un metodo statico del tipo contenente.
- Assegnare il riferimento delegato generato a un campo di istanza dell'oggetto contenitore.
Risultato: il compilatore crea un oggetto di chiusura che fa riferimento all'oggetto che ha creato la lambda, quando non ha motivo di: la destinazione "interna" del delegato è un metodo statico e i membri dell'istanza della lambda-creando-oggetto non devono essere (e non essere) toccato quando viene eseguito il delegato. In effetti, il compilatore si comporta come se il programmatore avesse catturato this
senza motivo.
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Il codice generato da una build di rilascio (decompilato in C # "più semplice") è simile al seguente:
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);
}
}
Osservare che il <>4__this
campo dell'oggetto di chiusura è popolato con un riferimento a un oggetto ma non viene mai letto (non c'è motivo).
Quindi cosa sta succedendo qui? La specifica della lingua lo consente? Si tratta di un bug del compilatore / stranezza o c'è una buona ragione (che mi manca chiaramente) per la chiusura per fare riferimento all'oggetto? Questo mi rende ansioso perché sembra una ricetta per programmatori felici della chiusura (come me) per introdurre inconsapevolmente strane perdite di memoria (immagina se il delegato fosse usato come gestore di eventi) nei programmi.
this
.