การตรวจสอบนี้ดึงดูดความสนใจของคุณต่อความจริงที่ว่ามีการบันทึกค่าการปิดมากกว่าที่เห็นได้ชัดซึ่งมีผลกระทบต่ออายุการใช้งานของค่าเหล่านี้
พิจารณารหัสต่อไปนี้:
using System;
public class Class1 {
private Action _someAction;
public void Method() {
var obj1 = new object();
var obj2 = new object();
_someAction += () => {
Console.WriteLine(obj1);
Console.WriteLine(obj2);
};
// "Implicitly captured closure: obj2"
_someAction += () => {
Console.WriteLine(obj1);
};
}
}
ในการปิดครั้งแรกเราจะเห็นว่าทั้ง obj1 และ obj2 นั้นถูกจับอย่างชัดเจน เราสามารถเห็นสิ่งนี้ได้เพียงแค่ดูรหัส สำหรับการปิดครั้งที่สองเราจะเห็นว่า obj1 นั้นถูกจับภาพไว้อย่างชัดเจน แต่ ReSharper เตือนเราว่า obj2 นั้นถูกจับโดยปริยาย
นี่เป็นเพราะรายละเอียดการใช้งานในคอมไพเลอร์ C # ในระหว่างการรวบรวมการปิดจะถูกเขียนใหม่ในคลาสที่มีเขตข้อมูลที่เก็บค่าที่บันทึกไว้และวิธีการที่แสดงถึงการปิดตัวเอง คอมไพเลอร์ C # จะสร้างคลาสส่วนตัวดังกล่าวเพียงหนึ่งคลาสต่อวิธีและถ้ามีการปิดมากกว่าหนึ่งวิธีในคลาสนั้นคลาสนี้จะมีวิธีการหลายวิธีหนึ่งสำหรับแต่ละการปิดและจะรวมถึงค่าที่จับทั้งหมดจากการปิดทั้งหมด
ถ้าเราดูโค้ดที่คอมไพเลอร์สร้างมันจะมีลักษณะเช่นนี้เล็กน้อย (บางชื่อถูกลบล้างเพื่อให้ง่ายต่อการอ่าน):
public class Class1 {
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public object obj1;
public object obj2;
internal void <Method>b__0()
{
Console.WriteLine(obj1);
Console.WriteLine(obj2);
}
internal void <Method>b__1()
{
Console.WriteLine(obj1);
}
}
private Action _someAction;
public void Method()
{
// Create the display class - just one class for both closures
var dc = new Class1.<>c__DisplayClass1_0();
// Capture the closure values as fields on the display class
dc.obj1 = new object();
dc.obj2 = new object();
// Add the display class methods as closure values
_someAction += new Action(dc.<Method>b__0);
_someAction += new Action(dc.<Method>b__1);
}
}
เมื่อวิธีการทำงานมันจะสร้างคลาสการแสดงผลซึ่งจับค่าทั้งหมดสำหรับการปิดทั้งหมด ดังนั้นแม้ว่าจะไม่ได้ใช้ค่าในการปิดอย่างใดอย่างหนึ่ง แต่ก็จะยังคงถูกจับ นี่คือการจับ "โดยนัย" ที่ ReSharper กำลังเน้น
ความหมายของการตรวจสอบนี้คือค่าการปิดที่จับได้โดยปริยายจะไม่ถูกเก็บขยะจนกว่าการปิดตัวเองจะเป็นการเก็บขยะ อายุการใช้งานของค่านี้จะเชื่อมโยงกับอายุการใช้งานของการปิดที่ไม่ได้ใช้ค่าอย่างชัดเจน หากการปิดนั้นใช้เวลานานนี่อาจมีผลเสียกับรหัสของคุณโดยเฉพาะถ้าค่าที่บันทึกไว้มีขนาดใหญ่มาก
โปรดทราบว่าแม้ว่านี่จะเป็นรายละเอียดการใช้งานของคอมไพเลอร์ แต่ก็มีความสอดคล้องกันระหว่างเวอร์ชันและการใช้งานเช่น Microsoft (ก่อนและหลังโรสลิน) หรือคอมไพเลอร์ของโมโน การใช้งานจะต้องทำงานตามที่อธิบายไว้เพื่อให้สามารถจัดการประเภทการปิดหลายรายการได้อย่างถูกต้อง ตัวอย่างเช่นหากการปิดหลายรายการจับ int แล้วพวกเขาจะต้องจับอินสแตนซ์เดียวกันซึ่งสามารถเกิดขึ้นได้กับคลาสที่ซ้อนกันไพรเวตส่วนตัวเดียว ผลข้างเคียงของสิ่งนี้คือว่าอายุการใช้งานของค่าที่บันทึกไว้ทั้งหมดจะเป็นอายุการใช้งานสูงสุดของการปิดใด ๆ ที่จับค่าใด ๆ