2012-06-11 71 views
2

我超出範圍之後析構函數有問題(它正在調用,但過了一段時間,需要在窗體上進行操作,例如更改單選按鈕),也許我的錯誤碼。看看:C#析構函數超出範圍後不會調用

namespace WindowsFormsApplication2 
{ 
    public partial class Form1 : Form 
    { 

     public Form1() 
     { 
      InitializeComponent(); 
      EventLogger.Print += delegate(string output) 
      { if (!textBox1.IsDisposed) this.Invoke(new MethodInvoker(() => textBox1.AppendText(output + Environment.NewLine)), null); }; 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      TestClass test = new TestClass(); 
     } 
    } 
    public static class EventLogger 
    { 
     public delegate void EventHandler(string output); 
     public static event EventHandler Print; 
     public static void AddLog(String TextEvent) 
     { 
      Print(TextEvent); 
     } 
    } 
    public class TestClass 
    { 
     public TestClass() 
     { 
      EventLogger.AddLog("TestClass()"); 
     } 
     ~TestClass() 
     { 
      EventLogger.AddLog("~TestClass()"); 
     } 
    } 

} 
+7

我建議你使用IDisposable模式而不是析構函數。特別是如果你沒有OS級別的句柄。你不應該使用析構函數。 – DarthVader

+0

永遠不要依賴析構函數。 –

+0

另一個說明。你甚至有問題嗎?析構函數在GC時間被調用,並且無法控制。你不能迫使GC進行清理。無論如何,你甚至不需要代碼中的任何desctructor。 – DarthVader

回答

9

對,因爲這不是C++。在對象離開它的聲明範圍之後,終結器(不像C++中的析構函數)不能被保證立即被調用,它在GC決定突襲並在你之後清理時被調用。

請問您爲什麼要使用終結器?你是否保持對非託管資源的引用,這些資源需要儘可能確定地釋放(如果是這樣,請閱讀IDisposable接口)? C#終結器的用例很少,而且實現它們並不常見。

+0

當我不使用表單應用程序,但控制檯,一切都OK。 – user1112008

+0

@ user1112008你不需要爲你的代碼析構函數。你爲什麼覺得你需要它? – DarthVader

+0

我只需要自動化UI。每個類都以文本的形式包含在窗體的listview中。當它創建它從構造函數添加到列表視圖,然後超出範圍(析構函數),它從列表視圖中刪除。對不起我的英語不好。 – user1112008

3

C#不是C++。 Destructors don't run synchronously

代碼中沒有錯誤,但它看起來像您可能需要爲您的類實現「IDisposable模式」,以便爲調用者提供一種保證對象的某些銷燬同步執行的方法。

0

終結器不適用於在超出範圍後立即調用。當對象被垃圾收集時,它會被調用,這可能會在超出範圍之後的幾毫秒到幾天之間。

終結器不適用於這種類型的代碼。它只用於資源清理。

你不能強迫它在超出範圍之後立即做某事,但你可以在超出範圍之前立即告訴它,用Close()或類似的方法表示該對象已完成使用。

例如:

private void button1_Click(object sender, EventArgs e) 
{ 
    TestClass test = new TestClass(); 
    // do stuff 
    test.Close(); 
} 

注意:您可以實現IDisposable,如已提出,但這種使用並不完全適合預期用途的IDisposable,所以雖然它會工作,這是一個有點hackish 。

+0

是的,但將它放入析構函數的美妙之處在於(在C++中),只要對象超出範圍,就會調用它。意思是當你從函數返回時,析構函數被調用。這樣可以避免在函數中的每個return語句之前調用'test.Close()'。 –

2

對於我們這些誰是更舒適與C++模式是非常有用的檢查了文檔的IDisposable接口:

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

不幸的是我剛剛嘗試過了,它不工作,我我喜歡。我使用自動對象來保存GUI遊標的當前狀態,切換到等待遊標並在對象超出作用域時恢復原始遊標。 IDisposable接口確實會導致遊標被恢復,但不會立即生效 - 所以Wait Cursor顯示的時間太長。太糟糕了,因爲這是一個非常有用的模式。