C#中的解構器[翻譯]
來源:互聯網
上載者:User
C#中的解構器
引言
在公司專屬應用程式開發世界,效能,靈活性和安全性是最重要的。我作為一個VC++程式員開始我的職業生涯,並且在一個晴朗的早晨,我被轉到了Web開發部。像每個C++程式員一樣,我也很失落。我想每個像Tom,Dick甚至Harry能用HTML編程。然而,不久我就發現真正的挑戰是生產高效能的,靈活的可靠的應用程式。綜上所述,Web環境松耦合的,不分國界的本質將使你永遠神往。
為了製作高效能的靈活的應用程式,用最佳化的方式使用你的資源是至關重要的。一個技巧是儘可能晚地使用你的資源並且在使用後儘快釋放它。我在這裡的意圖是描述在C#中的對象清除機制。
解構器
我們知道,‘解構器’被用來清除類的案例。當我們在C#中使用解構器是,我們必須記住以下幾點:
一個類只能有一個解構器。
解構器不能被繼承或重載。
解構器不能被調用。他們是自動被(編譯器)調用的。
解構器不能帶修飾或參數。
下面是類MyClass解構器的一個聲明:
~ MyClass()
{
// Cleaning up code goes here
}
程式員不能控制解構器何時將被執行因為這是由垃圾收集器決定的。垃圾收集器檢查不在被應用程式使用的對象。它認為這些條件是符合清楚的並且收回它們的記憶體。解構器也在程式退出時被調用。當解構器執行時其背後所發生的那一幕是解構器隱式調用對象基類的Object.Finalize方法。因此上述解構器代碼被隱含轉化成:
protected override void Finalize()
{
try
{
// Cleaning up .
}
finally
{
base.Finalize();
}
}
現在,讓我們看一個解構器怎樣被調用的例子。我們有三個類A,B和C 。B派生自A,C派生自B。每個類有它們自己的構造器和解構。在類App的main函數中,我們建立C的對象。
using System;
class A
{
public A()
{
Console.WriteLine("Creating A");
}
~A()
{
Console.WriteLine("Destroying A");
}
}
class B:A
{
public B()
{
Console.WriteLine("Creating B");
}
~B()
{
Console.WriteLine("Destroying B");
}
}
class C:B
{
public C()
{
Console.WriteLine("Creating C");
}
~C()
{
Console.WriteLine("Destroying C");
}
}
class App
{
public static void Main()
{
C c=new C();
Console.WriteLine("Object Created ");
Console.WriteLine("Press enter to Destroy it");
Console.ReadLine();
c=null;
//GC.Collect();
Console.Read();
}
}
正如我們預料的,基類的構造器將會被執行並且程式會等待使用者按‘enter’。當這個發生,我們把類C的對象置為null.但解構器沒有被執行..!!??正像我們所說的,程式員無法控制解構器何時被執行因為這是由垃圾搜集器決定的。但程式退出時解構器被調用了。你能通過重新導向程式的o/p到文字檔來檢查這個。我將它輸出在這裡。注意到基類的解構器被調用了,因為在背後base.Finalize()被調用了。
Creating A
Creating B
Creating C
Object Created
Press enter to Destroy it
Destroying C
Destroying B
Destroying A
所以,如果一旦你使用完對象你就想調用解構器,你該怎麼做?有兩個方法:
調用垃圾搜集器來清理。
實現IDisposable的Dispose方法。
調用垃圾搜集器
你能通過調用GC.Collect方法強制垃圾搜集器來清理記憶體,但在大多數情況下,這應該避免因為它會導致效能問題。在上面的程式中,在GC.Collect()處移除注釋。編譯並運行它。現在,你能看到解構器在控制台中被執行了。
實現IDisposable介面
IDisposable 介面包括僅有的一個公用方法,其聲明為void Dispose()。我們能實現這個方法來關閉或釋放非託管資源如實現了這個介面的類案例所控制的檔案,流,和控制代碼等。這個方法被用做所有任務聯合對象的資源釋放。當實現了這個方法,對象必須尋求確保所有擁有的資源被繼承結構中關聯的資源也釋放(不能把握,翻不出來)。
class MyClass:IDisposable
{
public void Dispose()
{
//implementation
}
}
當我們實現了IDisposable介面時,我們需要規則來確保Dispose被適當地調用。
聯合使用解構器和IDisposable介面
Public class MyClass:IDisposable
{
private bool IsDisposed=false;
public void Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}
protected void Dispose(bool Diposing)
{
if(!IsDisposed)
{
if(Disposing)
{
//Clean Up managed resources
}
//Clean up unmanaged resources
}
IsDisposed=true;
}
~MyClass()
{
Dispose(false);
}
}
在這裡重載了Dispose(bool)來做清理工作,並且所有的清理代碼都僅寫在這個方法中。這個方法被解構器和IDisposable.Dispose()兩著調用。我們應該注意Dispose(bool)沒有在任何地方被調用除了在IDisposable.Dispose()和解構器中。
當一個客戶調用IDisposable.Dispose()時,客戶特意地想要清理託管的和非託管資源,並且因此完成清理工作。有一件你必須注意的事情是我們在清理資源之後立即調用了GC.SupressFinalize(this)。這個方法通知垃圾搜集器不需要調用解構器,因為我們已經做了清理。
注意上面的例子,解構器使用參數false調用Dispose。這裡,我們確信垃圾搜集器搜集了託管資源。我們僅僅做非託管資源的清理。
結論
儘管如此我們花費一些時間實現IDisposable介面,如果客戶不能合適地調用它們會怎樣?為此C#有一個酷的解決方案。‘using’代碼塊。它看起來像這樣:
using (MyClass objCls =new MyClass())
{
}
當控制從using塊通過成功運行到結束或者拋出異常退出時,MyClass的IDispose.Dispose()將會被執行。記住你例示的對象必須實現System.IDisposable介面。using語句定義了哪個對象將被清除的一個範圍。