2012-03-06 58 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