解構函式是實現銷毀一個類的執行個體的方法成員。解構函式不能有參數,不能任何修飾符而且不能被調用。由於解構函式的目的與建構函式的相反,就加首碼‘~’以示區別。
雖然C#(更確切的說是CLR)提供了一種新的記憶體管理機制---自動記憶體管理機制(Automatic memory management),資源的釋放是可以通過“記憶體回收行程” 自動完成的,一般不需要使用者幹預,但在有些特殊情況下還是需要用到解構函式的,如在C#中非託管資源的釋放。
資源的釋放一般是通過"記憶體回收行程"自動完成的,但具體來說,仍有些需要注意的地方:
1. 實值型別和參考型別的引用其實是不需要什麼"記憶體回收行程"來釋放記憶體的,因為當它們出了範圍後會自動釋放所佔記憶體,因為它們都儲存在棧(Stack)中;
2. 只有參考型別的引用所指向的對象執行個體才儲存在堆(Heap)中,而堆因為是一個自由儲存空間,所以它並沒有像"棧"那樣有生存期("棧"的元素彈出後就代表生存期結束,也就代表釋放了記憶體),並且要注意的是,"記憶體回收行程"只對這塊地區起作用;
using System;
using System.Collections.Generic;
using System.Text;
namespace NET.MST.Third.FinalizeDispose
{
public class FinalizeDisposeBase : IDisposable
{
// 標記對象是否已被釋放
private bool _disposed = false;
// Finalize方法:
~FinalizeDisposeBase()
{
Dispose(false);
}
// 這裡實現了IDispose中的 Dispose方法
public void Dispose()
{
Dispose(true);
//告訴GC此對象的Finalize方法不再需要調用
GC.SuppressFinalize(true);
}
//在這裡做實際的析構工作
//申明為虛方法以供子類在有必要時重寫
protected virtual void Dispose(bool isDisposing)
{
// 當對象已經被析構時,不再執行
if (_disposed)
return;
if (isDisposing)
{
//在這裡釋放託管資源
//只在使用者調用Dispose方法時執行
}
//在這裡釋放非託管資源
//標記對象已被釋放
_disposed = true;
}
}
public sealed class FinalizeDispose : FinalizeDisposeBase
{
private bool _mydisposed = false;
protected override void Dispose(bool isDisposing)
{
// Don't dispose more than once.
if (_mydisposed)
return;
if (isDisposing)
{
//在這裡釋放託管的並且在這個類型中申明的資源
}
//在這裡釋放非託管的並且在這個類型中申明的資源
//調用父類的Dispose方法來釋放父類中的資源
base.Dispose(isDisposing);
// 設定子類的標記
_mydisposed = true;
}
static void Main()
{
}
}
}
需要釋放非託管資源時,就必須通過寫代碼的方式來解決。通常是使用解構函式釋放非託管資源,將使用者自己編寫的釋放非託管資源的程式碼片段放在解構函式中即可。需要注意的是,如果一個類中沒有使用到非託管資源,那麼一定不要定義解構函式,這是因為對象執行了解構函式,那麼"記憶體回收行程"在釋放託管資源之前要先調用解構函式,然後第二次才真正釋放託管資源,這樣一來,兩次刪除動作的花銷比一次大多的。