Odpowiadałem na pytanie o możliwość domknięć (uzasadnionych) wydłużania czasu życia obiektów, kiedy natknąłem się na jakiś niezwykle ciekawy gen kodu ze strony kompilatora C # (4.0, jeśli to ma znaczenie).
Najkrótsza reprodukcja, jaką mogę znaleźć, jest następująca:
- Utwórz lambdę, która przechwytuje lokalną podczas wywoływania metody statycznej typu zawierającego.
- Przypisz wygenerowane odwołanie do delegata do pola wystąpienia obiektu zawierającego.
Wynik: kompilator tworzy obiekt zamknięcia, który odwołuje się do obiektu, który utworzył lambdę, gdy nie ma powodu - „wewnętrznym” celem delegata jest metoda statyczna , a elementy składowe instancji obiektu tworzącego lambdę nie muszą być (i nie są) dotykane podczas wykonywania delegata. W rzeczywistości kompilator zachowuje się tak, jak programista przechwycił this
bez powodu.
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Wygenerowany kod z kompilacji wydania (zdekompilowany do „prostszego” C #) wygląda następująco:
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);
}
}
Zauważ, że <>4__this
pole obiektu zamknięcia jest wypełnione odwołaniem do obiektu, ale nigdy nie jest odczytywane (nie ma powodu).
Więc co się tutaj dzieje? Czy specyfikacja języka na to pozwala? Czy jest to błąd / dziwność kompilatora, czy też istnieje dobry powód (którego wyraźnie mi brakuje), aby zamknięcie odwoływało się do obiektu? To mnie niepokoi, ponieważ wygląda to na przepis na zadowolonych z zamknięcia programistów (takich jak ja) na nieświadome wprowadzanie dziwnych wycieków pamięci (wyobraź sobie, że delegat był używany jako program obsługi zdarzeń) do programów.
this
.