สิ่งที่คุณขาดหายไปคือคอมไพเลอร์ยืดอายุการใช้งานx
ตัวแปรของคุณไปจนถึงจุดสิ้นสุดของวิธีการที่กำหนดไว้ - นั่นเป็นเพียงบางสิ่งที่คอมไพเลอร์ทำ - แต่มันทำเพื่อ DEBUG build เท่านั้น
หากคุณเปลี่ยนรหัสเพื่อให้ตัวแปรถูกกำหนดในวิธีแยกต่างหากมันจะทำงานตามที่คุณคาดหวัง
ผลลัพธ์ของรหัสต่อไปนี้คือ:
False
True
และรหัส:
using System;
namespace ConsoleApp1
{
class Finalizable
{
~Finalizable()
{
_extendMyLifetime = this;
}
public static bool LifetimeExtended => _extendMyLifetime != null;
static Finalizable _extendMyLifetime;
}
class Program
{
public static void Main()
{
test();
Console.WriteLine(Finalizable.LifetimeExtended); // False.
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Finalizable.LifetimeExtended); // True.
}
static void test()
{
new Finalizable();
}
}
}
โดยพื้นฐานแล้วความเข้าใจของคุณถูกต้อง แต่คุณไม่รู้ว่าคอมไพเลอร์ลับๆล่อๆนั้นจะทำให้ตัวแปรของคุณยังมีชีวิตอยู่จนกระทั่งหลังจากที่คุณโทรGC.Collect()
ถึงแม้ว่าคุณจะตั้งค่าเป็นโมฆะอย่างชัดเจนก็ตาม!
ดังที่ฉันได้กล่าวไว้ข้างต้นสิ่งนี้เกิดขึ้นเฉพาะกับการสร้าง DEBUG - เพื่อให้คุณสามารถตรวจสอบค่าสำหรับตัวแปรท้องถิ่นในขณะที่ทำการดีบักจนถึงจุดสิ้นสุดของวิธีการ (แต่นั่นเป็นเพียงการคาดเดา!)
โค้ดต้นฉบับทำงานได้ตามที่คาดไว้สำหรับบิลด์รีลีส - ดังนั้นโค้ดต่อไปนี้จะออกมาfalse, true
สำหรับบิลด์ RELEASE และfalse, false
สำหรับบิลด์ DEBUG:
using System;
namespace ConsoleApp1
{
class Finalizable
{
~Finalizable()
{
_extendMyLifetime = this;
}
public static bool LifetimeExtended => _extendMyLifetime != null;
static Finalizable _extendMyLifetime;
}
class Program
{
public static void Main()
{
new Finalizable();
Console.WriteLine(Finalizable.LifetimeExtended); // False.
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Finalizable.LifetimeExtended); // True iff RELEASE build.
}
}
}
ภาคผนวก: โปรดทราบว่าถ้าคุณทำบางสิ่งบางอย่างใน finalizer สำหรับคลาสที่ทำให้การอ้างอิงถึงอ็อบเจ็กต์ที่ถูกสรุปให้สามารถเข้าถึงได้จากรูทโปรแกรมแล้ววัตถุนั้นจะไม่ถูกเก็บขยะเว้นแต่และจนกว่าวัตถุนั้นจะไม่อยู่อีกต่อไป อ้างอิง
ในคำอื่น ๆ คุณสามารถให้วัตถุ "อยู่ในการดำเนินการ" ผ่าน finalizer นี่ถือเป็นการออกแบบที่ไม่ดีเลยทีเดียว!
ตัวอย่างเช่นในรหัสด้านบนที่เราทำ_extendMyLifetime = this
ใน finalizer เรากำลังสร้างการอ้างอิงใหม่ไปยังวัตถุดังนั้นตอนนี้มันจะไม่ถูกเก็บรวบรวมขยะจนกว่า_extendMyLifetime
(และการอ้างอิงอื่น ๆ ) จะไม่มีการอ้างอิงอีกต่อไป
Person1
?Person
ผมเห็นเท่านั้น สุดท้าย: ดูdocs.microsoft.com/dotnet/csharp/programming-guide/…สำหรับการทำงานของ finalizers