2010-04-06 486 views
5

我是新來的.NET ..和我很困惑,在C#析構函數機制..please澄清爲什麼Finalize方法不能覆蓋

在C#中的析構函數轉換由CLR敲定方法。 如果我們嘗試覆蓋它(不使用析構函數),將會出錯 錯誤2請勿重寫object.Finalize。相反,提供一個析構函數。

但似乎mscorlib.dll中的Object calss實現已將finalize定義爲protected override void Finalize(){},那麼爲什麼我們不能重寫它,那是什麼虛函數。

爲什麼這樣的設計是否與C++析構函數概念一致?

另外,當我們進入對象類的定義時,沒有提及finalize方法,那麼hmscorlib.dll定義如何顯示finalize函數。 這是否意味着默認的析構函數被轉換爲finalize方法。

public class Object 
{  

    public Object(); 
    public virtual bool Equals(object obj);   
    public static bool Equals(object objA, object objB);  
    public virtual int GetHashCode();  
    public Type GetType();  
    protected object MemberwiseClone(); 
    public static bool ReferenceEquals(object objA, object objB); 
    public virtual string ToString(); 
} 

回答

0

要覆蓋Finalize(),必須使用終結器語法。 CLI在內部對某些內容使用固定名稱,如全部爲的實例構造函數名爲.ctor,以及所有名爲.cctor的靜態構造函數。當C#編譯器寫入輸出程序集時,它確保爲其發出的項目使用正確的名稱,其中包括將析構函數的名稱寫爲Finalize()而不是~T()。其他.NET語言的編譯器也必須遵循這些相同的規則來進行自己的語義。

class A 
{ 
    ~A() { /* ... */ } 
} 

對於何時終結的怎麼樣,找這裏的許多其他問題與終結和IDisposable處理。

+1

我認爲他們明白,並且正在尋求解釋_why_。 – 2010-04-06 17:48:59

4

'爲什麼這樣?'
由設計決定。可能與C++匹配,但它確實無關緊要。

怎樣的hmscorlib.dll定義 顯示的finalize函數

有可能是在C#編譯器的特別干預。再次,它沒有實際的區別。

如果你真的需要一個終結器,寫一個析構函數。更重要的是:你幾乎從不需要。

要看看這個選擇有多麼隨意:在VB中你可以override Finalize。而這兩種語言可以非常高興地使用(並繼承)其他類型。

+3

+1「你幾乎從不需要」。通常需要'IDisposable'接口。 – 2010-04-06 17:53:54

+0

@Richard,是的,IDisposable類經常但不總是有析構函數。沒有IDisposable的析構函數非常罕見(甚至懷疑)。 – 2010-04-06 17:58:13

0

這是否意味着默認的析構函數轉化爲最終確定方法

是,默認的(唯一的)析構函數語法C#編譯爲Finalize方法。這很可能爲C++開發人員提供了一種熟悉的語法。有關更多信息,請參閱Destructors on MSDN

+1

C#中沒有默認的析構函數。 – 2010-04-06 18:00:37

0

在C++中,你需要析構函數爲虛擬的。究其原因,這是它是如何在調用C++

A a = new B() //where B derived from A 
delete a; 

有點生疏了,所以請原諒我,如果我錯了。但是請看,刪除被傳遞了一個可能是基類的引用。

在C#中,您不會調用終結器。它由垃圾收集器在內部調用。沒有理由垃圾收集器會對之前分配的參考類型感興趣,並直接獲取對象:)

現在,終結器只是從C++獲取語法。因此混亂。

其他人在說什麼是,你通常不需要最終確定。這就是爲什麼。

如果您實現了IDisposable,那麼可以藉助「using」語句來決定變量的範圍並在需要時進行處置。通過Finalization,GC決定何時調用該方法。這意味着,如果您需要釋放資源,時間可能是錯誤的。

希望這會有所幫助。

20

剛剛接觸.NET,我對C#中的析構函數機制感到困惑。請澄清。

當然。我同意這令人困惑。

在C#析構函數被轉換由CLR敲定方法。

正確。那麼,我會說這是由C#編譯器完成的,而不是CLR,但我理解你的意思。

如果我們嘗試覆蓋它(不使用析構函數),將會得到一個錯誤「不要覆蓋object.Finalize,而是提供一個析構函數。」

正確。

似乎在mscorlib.dll Object類實現已敲定定義爲保護覆蓋無效的Finalize(){}

正確的。

那麼爲什麼我們不能重寫呢?這是一個虛擬功能。

因爲接下來會有兩個的方法來編寫析構函數。這會讓人困惑。我們希望只有一種方法來編寫析構函數。

爲什麼這樣的設計?它是否與C++析構函數概念一致?

這是一個原因,是的。還有其他原因。這裏有幾個:

  • 通過邏輯分離的「析構函數」的概念和「覆蓋finalize方法,」我們有可能通過在其他環境中其他一些機制實現析構函數。這種情況還沒有發生,但可能發生的事情是,將來我們會編寫一個C#版本,例如,用於在具有與標準CLR語義不同的垃圾收集器語義的環境中構建設備驅動程序。在那個環境中,析構函數的語義可能更像C++析構函數的語義,而不像GC終結器。

  • 終結者是非常非常特殊的方法。你不能像常規方法那樣稱呼他們;只有垃圾收集器可以調用它們。他們有不同的異常處理規則。他們必須確保在派生類終結器之後嚴格調用基類終結器。它們非常特殊,將它們暴露爲任何其他方法似乎是危險的。如果你有一種方法就是坐在那裏,你可以打電話,你可以放入任何你想要的東西,等等,這很容易忘記終結者有多特別。有一個特殊的語法強調這是特殊的代碼。

而且當我們去的對象類的定義,有finalize方法中沒有提及,那麼請問在mscorlib.dll中定義顯示的finalize函數。

假設我們在名爲MagicUnicorn的對象瀏覽器中顯示了一個方法,並且如果您試圖調用它或覆蓋它,您會看到一個錯誤,說「不要那樣做!」。如果你不能用它做任何事情,爲什麼還要展示MagicUnicorn方法?這只是無益的噪音。

現在,如果你反彙編mscorlib,那當然真的有特殊的Finalize方法。

是否意味着默認析構函數轉換爲finalize方法。

是的。

+0

有沒有什麼辦法可以在不使用'GC.SuppressFinalize()'和'GC.KeepAlive()'的名稱有效硬編碼的情況下正確使用析構函數*?如果C#在需要時提供了調用此類函數的語法(無需使用特定於框架的名稱),我可能會在析構函數語法中看到一些值。另一方面,如果編寫一個適當的自清潔對象需要至少使用兩個特定於框架的'GC。*'方法,我不確定這個難題的一小部分是特定於語言的特定值而不是特定於框架。我錯過了什麼嗎? – supercat 2012-06-18 23:22:18

相關問題