2012-03-06 55 views
4

比方說,我有一個名爲Dialog的類擴展了Form。還有的對話框和確定按鈕上的文本框,當用戶點擊OK,通過一個事件返回的文本框的值:從C#和垃圾收集中的事件中分離匿名偵聽器

public class Dialog: Form 
{ 
    public delegate void onDialogValueReturned(object sender, DialogEventArgs e); 
    public event onDialogValueReturned DialogValueReturned; 
. 
. 
. 

    OKButton.Click += (sender, evt) => 
     { 
      DialogEventArgs e = new DialogEventArgs(); 
      e.Value =myTextBox.Text;     
      DialogValueReturned(this, e); 
      this.Close(); 
     }; 

在我的呼喚形式,我實例化的本地方法的對話:

private void Foo() 
    { 
     Dialog D = new Dialog("blah blah"); 
     D.DialogValueReturned += (dialog, evt) => 
      { 

       //do something with evt.Value 

      }; 


     D.ShowDialog(); 
    } 

該對話框可能會在一天中由用戶實例化數十次甚至數百次。

當作用域離開私有方法(包括匿名偵聽器的所有管道)時,垃圾回收器是否自動清理與對話框實例有關的所有內容?

由於

+0

'Form'實現'IDisposable',所以你可以簡單地在你完成它的時候處理一個表單。應該沒有必要。 – 2012-03-06 20:23:23

回答

2

事件的發佈者保留了對每個訂閱者的強烈參考。如果發佈者的壽命比訂閱者長,那麼當發佈者在場時,訂閱者將被固定在內存中。

在您的示例中,發佈程序只存在於您的私有方法的範圍內,因此對話框和處理程序將在方法返回後的某個時間點被垃圾回收。

我建議遵守dot net framework guidelines for publishing an event,它建議使用受保護的虛擬方法來調用事件。

+0

與lambda方法相比,我沒有看到所有額外工作的好處。不說沒有好處 - 我只是不認識它。鑑於對象的範圍僅限於私有方法,因此將匿名處理程序直接附加到事件的缺點是什麼? – Tim 2012-03-16 19:09:03

+0

在這種情況下,它很好。但是,如果您在大型團隊或大型項目中工作,則一致性是可維護性和可重用性的關鍵。試想一下,在一個項目中,30位開發人員都有自己的編寫事件處理代碼的方式! – sga101 2012-03-17 20:49:53

+0

這是一個很好的理由,但我最關心的是運行時和內存管理問題。 – Tim 2012-03-19 14:36:28

0

匿名功能將導致具有由編譯器自動生成其名稱的成員函數。編譯器生成的名稱將包含C#中非法的字符,以確保您不能用同名的名稱命名其他成員。除此之外,它將與綁定到事件的常規方法表現完全相同,因此所涉及的所有資源都將被垃圾收集。

作爲設計筆記,由於您對從對話返回的值感興趣,因此我建議不要使用事件來通知對話窗口已關閉。相反,您可以將代碼封裝在一個靜態方法中,例如,您可以在其中打開對話框,等待事件循環,直到關閉對話框並從用戶讀取輸入,以更合適的格式返回輸入數據進一步處理。這將需要你打開一個模式窗口。這裏是一個例子:

public class MyDialog : Form 
{ 
    // We can make the constructor private, as this class is instantiated only 
    // in the Show method. 
    private MyDialog() 
    { 
    } 

    // ... 

    public class ReturnValue 
    { 
     public string Foo { get; set; } 
     // ... 
    } 

    public static ReturnValue ShowModal(/* any params, if required */) 
    { 
     ReturnValue result = new ReturnValue(); 
     MyDialog dialog = new MyDialog(); 

     if(DialogResult.OK == dialog.ShowDialog(null)) 
     { 
      // We can access private members like txtFoo since we are within the class. 
      result.Foo = dialog.txtFoo.Text; 

      // ... 
     } 

     return result; 
    } 
} 
+0

result = new MyDialog()? – 2012-03-07 13:04:35

+0

對不起,我匆匆發貼。我糾正了我的錯誤。 – npclaudiu 2012-03-07 21:59:01