Я відповідав на питання про можливість закриття (законно) продовження життя об'єкта, коли я зіткнувся з деяким надзвичайно цікавим кодовим кодом з боку компілятора C # (якщо це має значення 4,0).
Найкоротший докір, який я можу знайти, є наступним:
- Створіть лямбда, яка захоплює локальний під час виклику статичного методу, що містить тип.
- Призначте згенерований посилання делегата полем екземпляра об'єкта, що містить.
Результат: Компілятор створює об'єкт закриття, який посилається на об'єкт, який створив лямбда, коли у нього немає підстав - "внутрішня" ціль делегата є статичним методом, і членам екземпляра об'єкта, що створює лямбда, не потрібно не торкатися, коли делегат виконується. Ефективно компілятор діє так, як програміст захопив this
без причини.
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
Згенерований код із складання випуску (декомпільований на "простіший" C #) виглядає так:
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);
}
}
Зауважте, що <>4__this
поле об'єкта закриття заповнене посиланням на об'єкт, але з нього ніколи не читається (немає причини).
То що тут відбувається? Чи дозволяє це специфікація мови? Це помилка компілятора / дивацтва чи є вагомі причини (що я явно відсутня) для закриття для посилання на об'єкт? Це викликає занепокоєння, тому що це схоже на рецепт для програмістів, що радіють закриттю (як я), щоб мимоволі впроваджувати дивні витоки пам'яті (уявіть, якби делегат використовувався як обробник подій) у програми.
this
.