ฉันกำลังตอบคำถามเกี่ยวกับความเป็นไปได้ของการปิด (อย่างถูกกฎหมาย) การยืดอายุการใช้งานของวัตถุเมื่อฉันพบโค้ดโคเจนที่แปลกประหลาดมากในส่วนของคอมไพเลอร์ C # (4.0 ถ้าสำคัญ)
repro ที่สั้นที่สุดที่ฉันสามารถค้นหาได้มีดังต่อไปนี้:
- สร้างแลมบ์ดาที่จับภาพท้องถิ่นในขณะที่เรียกใช้ วิธีการคงที่ของประเภทที่มี
- กำหนดผู้รับมอบสิทธิ์อ้างอิงสร้างฟิลด์อินสแตนซ์ของวัตถุที่ประกอบด้วย
ผลลัพธ์: คอมไพเลอร์สร้างการปิดวัตถุที่อ้างอิงวัตถุที่สร้างแลมบ์ดาเมื่อไม่มีเหตุผล - เป้าหมาย 'ภายใน' ของผู้รับมอบสิทธิ์เป็นวิธีการคงที่และสมาชิกอินสแตนซ์ของแลมบ์ด้าการสร้างวัตถุไม่จำเป็น ถูก (และไม่) แตะเมื่อผู้รับมอบสิทธิ์ถูกดำเนินการ คอมไพเลอร์ทำหน้าที่เหมือนโปรแกรมเมอร์ที่จับได้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
จับ