ใน. NET ฉันควรใช้ภายใต้สถานการณ์GC.SuppressFinalize()ใด
การใช้วิธีนี้ทำให้ฉันได้เปรียบอะไร
ใน. NET ฉันควรใช้ภายใต้สถานการณ์GC.SuppressFinalize()ใด
การใช้วิธีนี้ทำให้ฉันได้เปรียบอะไร
คำตอบ:
SuppressFinalizeควรถูกเรียกโดยคลาสที่มี finalizer เท่านั้น กำลังแจ้ง Garbage Collector (GC) ว่าthisมีการล้างวัตถุอย่างสมบูรณ์
IDisposableรูปแบบที่แนะนำเมื่อคุณมี finalizer คือ:
public class MyClass : IDisposable
{
    private bool disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // called via myClass.Dispose(). 
                // OK to use any private object references
            }
            // Release unmanaged resources.
            // Set large fields to null.                
            disposed = true;
        }
    }
    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
}โดยปกติ CLR จะเก็บแท็บบนวัตถุด้วยตัวสร้างขั้นสุดท้ายเมื่อมันถูกสร้างขึ้น (ทำให้มีราคาแพงกว่าในการสร้าง) SuppressFinalizeบอก GC ว่าวัตถุได้รับการทำความสะอาดอย่างถูกต้องและไม่จำเป็นต้องไปยังคิวสุดท้าย ดูเหมือนว่า destructor ของ C ++ แต่ไม่ได้ทำอะไรคล้าย ๆ กัน
การSuppressFinalizeเพิ่มประสิทธิภาพนั้นไม่สำคัญเพราะวัตถุของคุณสามารถใช้งานได้นานรอคิว finalizer อย่าล่อลวงให้โทรหาSuppressFinalizeวัตถุอื่นในใจคุณ นั่นเป็นข้อบกพร่องร้ายแรงที่รอให้เกิดขึ้น
แนวทางการออกแบบแจ้งให้เราทราบว่าไม่จำเป็นต้องใช้เครื่องมือปรับแต่งขั้นสุดท้ายหากวัตถุของคุณใช้IDisposableแต่ถ้าคุณมีเครื่องมือสร้างขั้นสุดท้ายคุณควรใช้IDisposableเพื่ออนุญาตให้การล้างข้อมูลในชั้นเรียนของคุณเป็นไปอย่างราบรื่น
ส่วนใหญ่เวลาที่คุณควรจะได้รับไปด้วยIDisposableเพื่อล้างทรัพยากร คุณควรต้องมีเครื่องมือขั้นสุดท้ายเมื่อวัตถุของคุณเก็บทรัพยากรที่ไม่มีการจัดการไว้เท่านั้นและคุณต้องรับประกันว่าทรัพยากรเหล่านั้นได้รับการทำความสะอาดแล้ว
หมายเหตุ: บางครั้งผู้ทำโคเดอร์จะเพิ่ม finalizer เพื่อตรวจแก้จุดบกพร่องการสร้างIDisposableคลาสของตนเองเพื่อทดสอบว่ารหัสกำจัดIDisposableวัตถุอย่างเหมาะสม
public void Dispose() // Implement IDisposable
{
    Dispose(true);
#if DEBUG
    GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endifIDisposableไม่ได้sealedแล้วมันควรจะรวมถึงการเรียกร้องให้GC.SuppressFinalize(this) ถึงแม้ว่ามันจะไม่รวมถึง finalizer นี่เป็นสิ่งจำเป็นเพื่อให้แน่ใจว่าความหมายที่ถูกต้องสำหรับประเภทที่ได้รับซึ่งเพิ่ม finalizer ที่ผู้ใช้กำหนด แต่จะแทนที่เฉพาะDispose(bool)วิธีที่ได้รับการป้องกัน
                    sealedกล่าวถึงโดย @SamHarwell เป็นสิ่งสำคัญสำหรับคลาสที่ได้รับ ผลการ CodeAnalysis ใน ca1816 ca1063 + เมื่อเรียนไม่ได้ปิดผนึก SuppressFinalizeแต่การเรียนที่ปิดสนิทโดยไม่ต้องมีการปรับ
                    SupressFinalizeแจ้งให้ระบบทราบว่าสิ่งใดก็ตามที่จะต้องทำใน Finalizer นั้นเสร็จสิ้นแล้วดังนั้น Finalizer จึงไม่จำเป็นต้องถูกเรียก จาก. NET docs:
วัตถุที่ใช้อินเทอร์เฟซ IDisposable สามารถเรียกวิธีนี้จากนั้น IDisposable.Dispose วิธีการเพื่อป้องกันการเก็บขยะจากการเรียก Object.Finalize บนวัตถุที่ไม่ต้องการ
โดยทั่วไปแล้วDispose()วิธีการส่วนใหญ่ควรจะสามารถโทรGC.SupressFinalize()ได้เพราะมันควรจะล้างข้อมูลทุกอย่างที่จะต้องทำความสะอาดใน Finalizer
SupressFinalizeเป็นเพียงสิ่งที่ให้การเพิ่มประสิทธิภาพที่ช่วยให้ระบบไม่รบกวนการจัดคิววัตถุไปยังเธรด finalizer ที่เขียนถูกต้องDispose()/ finalizer GC.SupressFinalize()ควรทำงานอย่างถูกต้องโดยมีหรือไม่มีการเรียกไปยัง
ต้องเรียกใช้Disposeเมธอดนั้นกับวิธีการของออบเจ็กต์ที่ใช้งานIDisposableด้วยวิธีนี้ GC จะไม่เรียก Finalizer อีกครั้งหากมีคนเรียกDisposeเมธอด
Dispose(true);
GC.SuppressFinalize(this);หากวัตถุมี finalizer, .net ใส่การอ้างอิงในคิวการสรุป
เนื่องจากเรามีการโทรDispose(ture)เป็นวัตถุที่ชัดเจนดังนั้นเราจึงไม่ต้องการคิวการสรุปเพื่อทำงานนี้
ดังนั้นการโทรGC.SuppressFinalize(this)ลบการอ้างอิงในคิวการสรุป
ถ้าชั้นเรียนหรืออะไรที่ได้มาจากมันอาจถืออ้างอิงสดที่ผ่านมาเพื่อวัตถุที่มี finalizer แล้วอย่างใดอย่างหนึ่งGC.SuppressFinalize(this)หรือGC.KeepAlive(this)ควรจะเรียกว่าบนวัตถุหลังจากการดำเนินการใด ๆ ที่อาจได้รับผลกระทบโดย finalizer ว่าจึงมั่นใจได้ว่าวอน finalizer ไม่ทำงานจนกว่าจะเสร็จสิ้นการดำเนินการ
ค่าใช้จ่ายของGC.KeepAlive()และGC.SuppressFinalize(this)เป็นหลักเหมือนกันในคลาสใด ๆ ที่ไม่มี finalizer และคลาสที่มี finalizers ควรเรียกโดยทั่วไปGC.SuppressFinalize(this)ดังนั้นการใช้ฟังก์ชันหลังเนื่องจากขั้นตอนสุดท้ายของDispose()อาจไม่จำเป็นเสมอไป แต่จะไม่จำเป็น จะผิด.