完成項 (C# 程式設計手冊)

完成項 (過去稱為 解構函 式) ,可用來在垃圾收集行程收集類別實例時執行任何必要的最終清除。 在大部分情況下,您可以使用 或 衍生類別來包裝任何非受控控制碼,以避免撰寫完成項 System.Runtime.InteropServices.SafeHandle

備註

  • 無法在結構中定義完成項。 它們只能與類別搭配使用。
  • 一個類別只能有一個完成項。
  • 無法繼承或多載完成項。
  • 無法呼叫完成項。 會自動呼叫它們。
  • 完成項不會接受修飾詞,也不會包含參數。

例如,下列是 Car 類別的完成項宣告。

class Car
{
    ~Car()  // finalizer
    {
        // cleanup statements...
    }
}

完成項也可以實作為運算式主體定義,如下列範例所示。

public class Destroyer
{
   public override string ToString() => GetType().Name;

   ~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}

完成項會在物件的基底類別上隱含地呼叫 Finalize。 因此,會將完成項呼叫隱含地轉譯為下列程式碼︰

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

此設計表示從 Finalize 最衍生到最不衍生的所有實例,以遞迴方式呼叫 方法。

注意

不應該使用空的完成項。 類別包含完成項時,會在 Finalize 佇列中建立一個項目。 垃圾收集行程會處理此佇列。 當 GC 處理佇列時,它會呼叫每個完成項。 不必要的完成項,包括空的完成項、只呼叫基類完成項的完成項,或只呼叫條件式發出方法的完成項,會造成不必要的效能遺失。

程式設計人員在呼叫完成項時沒有控制權;垃圾收集行程決定何時呼叫垃圾收集行程。 記憶體回收行程會檢查應用程式不再使用的物件。 如果它認為物件適合進行完成,則會呼叫完成項 (如果有的話),並回收用來儲存物件的記憶體。 藉由呼叫 Collect 來強制垃圾收集,但大部分時候,應該避免此呼叫,因為它可能會產生效能問題。

注意

是否要執行完成項作為應用程式終止的一部分,都是 .NET 的每個實作所特有。 當應用程式終止時,.NET Framework對尚未進行垃圾收集的物件呼叫完成項進行每個合理的工作,除非對程式庫方法 GC.SuppressFinalize 的呼叫已隱藏這類清除 (,例如) 。 .NET 5 (包括 .NET Core) 和更新版本,不會在應用程式終止時呼叫完成項。 如需詳細資訊,請參閱GitHub問題 dotnet/csharpstandard #291

如果您需要在應用程式結束時可靠地執行清除,請註冊 System.AppDomain.ProcessExit 事件的處理常式。 該處理常式可確保 IDisposable.Dispose() (或, IAsyncDisposable.DisposeAsync()) 已針對在應用程式結束前需要清除的所有物件呼叫。 因為您無法直接呼叫 Finalize ,而且您無法保證垃圾收集行程會在結束前呼叫所有完成項,因此您必須使用 DisposeDisposeAsync 以確保資源已釋放。

使用完成項來釋放資源

一般而言,C# 在開發人員部分不需要太多記憶體管理,因為語言不是以垃圾收集為目標的執行時間。 這是因為 .NET 垃圾收集行程會隱含地管理物件的記憶體配置和釋放。 不過,當您的應用程式封裝非受控資源,例如 windows、檔案和網路連線時,您應該使用完成項來釋放這些資源。 適合完成物件時,記憶體回收行程會執行物件的 Finalize 方法。

明確釋放資源

如果您的應用程式使用過多的外部資源,則也建議您提供一種方式,以在記憶體回收行程釋放物件之前明確釋放資源。 若要釋放資源,請從 IDisposable 介面實 Dispose 作方法,以執行物件的必要清除。 這可以大幅改善應用程式效能。 即使對資源有明確的控制,完成項也會成為在呼叫 Dispose 方法失敗時清除資源的保護措施。

如需清除資源的詳細資訊,請參閱下列文章:

範例

下列範例會建立三個產生繼承鏈結的類別。 First 類別是基底類別、Second 衍生自 First,而 Third 衍生自 Second。 所有這三個都有完成項。 在 Main 中,會建立最高衍生性類別的執行個體。 此程式碼的輸出取決於應用程式目標 .NET 的實作:

  • .NET Framework:輸出顯示當應用程式終止時,會自動呼叫三個類別的完成項,以從最衍生到最小衍生的順序。
  • .NET 5 (包括 .NET Core) 或更新版本:沒有輸出,因為此 .NET 實作不會在應用程式終止時呼叫完成項。
class First
{
    ~First()
    {
        System.Diagnostics.Trace.WriteLine("First's finalizer is called.");
    }
}

class Second : First
{
    ~Second()
    {
        System.Diagnostics.Trace.WriteLine("Second's finalizer is called.");
    }
}

class Third : Second
{
    ~Third()
    {
        System.Diagnostics.Trace.WriteLine("Third's finalizer is called.");
    }
}

/* 
Test with code like the following:
    Third t = new Third();
    t = null;

When objects are finalized, the output would be:
Third's finalizer is called.
Second's finalizer is called.
First's finalizer is called.
*/

C# 語言規格

如需詳細資訊,請參閱C# 語言規格完成項一節。

另請參閱