Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

ความแตกต่างระหว่าง Finalize และ Dispose ใน C#

Finalize (Finalizer/Destructor)

  • Method: ~ClassName() (Syntax C#)
  • ถูกเรียกโดย Garbage Collector (GC) ก่อน Reclaim Memory
  • ไม่รับประกันเวลา (Non-deterministic)
  • ใช้ Cleanup Unmanaged Resources (File Handle, DB Connection, Native Pointer)
  • เป็นของ Object Class
  • ไม่ควบคุมได้ เรียกบังคับได้ด้วย GC.Collect() (ไม่แนะนำ - หยุด Performance)

Dispose (IDisposable Pattern)

  • Method: void Dispose() จาก Interface IDisposable
  • เรียก Explicitly โดย Developer (Deterministic)
  • Cleanup ทั้ง Managed และ Unmanaged Resources
  • ใช้กับ using Statement (Auto Dispose)
  • ควรเรียก GC.SuppressFinalize(this) เพื่อไม่ให้ GC เรียก Finalize ซ้ำ

ตัวอย่าง Finalize (Destructor)

public class Demo
{
    ~Demo()  // Finalizer - C# Syntax
    {
        Console.WriteLine("Finalize called");
        // Cleanup unmanaged resources only
    }
}

ตัวอย่าง Dispose Pattern (Standard)


public class ResourceHolder : IDisposable
{
    private bool _disposed = false;
    private IntPtr _unmanagedHandle; // Unmanaged resource
    private FileStream _managedResource; // Managed resource
    
    public ResourceHolder()
    {
        _unmanagedHandle = AllocateUnmanagedResource();
        _managedResource = new FileStream("data.txt", FileMode.Create);
    }
    
    // Public Dispose - เรียกโดย User Code
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this); // บอก GC ว่า Dispose แล้ว ไม่ต้อง Finalize
    }
    
    // Protected Virtual - ให้ Derived Class Override ได้
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Cleanup Managed Resources
                _managedResource?.Dispose();
                _managedResource = null;
            }
            
            // Cleanup Unmanaged Resources (เสมอ)
            if (_unmanagedHandle != IntPtr.Zero)
            {
                FreeUnmanagedResource(_unmanagedHandle);
                _unmanagedHandle = IntPtr.Zero;
            }
            
            _disposed = true;
        }
    }
    
    // Finalizer - Fallback ถ้า User ลืม Dispose
    ~ResourceHolder()
    {
        Dispose(false); // disposing = false → Cleanup Unmanaged เท่านั้น
    }
    
    // P/Invoke Example
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern IntPtr AllocateUnmanagedResource();
    
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern void FreeUnmanagedResource(IntPtr handle);
}

การใช้งานกับ using Statement


// แบบเดิม (C# 7-)
using (var resource = new ResourceHolder())
{
    // ใช้งาน resource
} // Dispose() เรียกอัตโนมัติที่นี่

// ใหม่ C# 8+ Using Declaration
using var resource = new ResourceHolder();
// Dispose เรียกตอนจบ Scope

สรุป: ควร Implement ทั้งคู่ (Microsoft Recommends)

  • Dispose(): เรียกได้ทันที Deterministic Cleanup
  • Finalize(): Safety Net ป้องกัน Resource Leak ถ้า User ลืม Dispose

สาระสำคัญ

ด้านFinalizeDispose
เรียกโดยGC (Non-deterministic)Developer (Deterministic)
CleanupUnmanaged OnlyManaged + Unmanaged
PerformanceCostly (Gen 2 Promotion)รวดเร็ว
ExceptionSwallowed by GCBubble up ปกติ