Я отвечал на question о возможности закрытия (законно) продления срока жизни объекта, когда я столкнулся с каким-то чрезвычайно любопытным кодом-gen со стороны компилятор С# (если это имеет значение).
Самый короткий реестр, который я могу найти, следующий:
- Создайте лямбду, которая захватывает локальную область при вызове статического метода содержащего типа.
- Назначить сгенерированную ссылку делегата полю экземпляра содержащего объекта.
Результат: компилятор создает объект-замыкатель, который ссылается на объект, который создал лямбда, когда у него нет причин - "внутренняя" цель делегата - это статический метод, а члены экземпляра лямбда-создания-объекта не требуется (и не затрагивается) при выполнении делегата. Фактически, компилятор действует так же, как программист захватил this
без причины.
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Сгенерированный код из сборки релиза (декомпилированный на "более простой" С#) выглядит следующим образом:
public void InstanceMethod()
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.<>4__this = this; // What 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);
}
}
Обратите внимание, что поле <>4__this
объекта замыкания заполняется ссылкой на объект, но никогда не читается (нет причин).
Итак, что здесь происходит? Означает ли спецификация языка? Является ли это ошибкой/странностью компилятора или есть веская причина (я, очевидно, отсутствует) для закрытия ссылки на объект? Это заставляет меня беспокоиться, потому что это похоже на рецепт для программистов с закрытым концом (например, я), чтобы невольно вводить странные утечки памяти (предположим, что делегат был использован как обработчик событий) в программы.