从C#和垃圾收集中的事件中分离匿名侦听器

假设我有一个名为Dialog的类,它扩展了Form。 对话框上有一个文本框和一个OK按钮,当用户单击OK时,将通过事件返回文本框值:

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(); } 

在一天中,用户可以将该对话框实例化数十次甚至数百次。

当作用域离开私有方法时,垃圾收集器是否会自动清除与对话框实例相关的所有内容,包括匿名侦听器的所有管道?

谢谢

活动的发布者保留对每个订阅者的强烈引用。 如果发布者的寿命比订阅者长,那么订阅者将在发布者存在时固定在内存中。

在您的示例中,发布者仅存在于私有方法的范围内,因此对话框和处理程序将在方法返回后的某个时刻进行垃圾回收。

我建议遵守dot net框架指南来发布事件 ,建议使用受保护的虚拟方法来调用事件。

匿名函数将导致成员函数的名称由编译器自动生成。 编译器生成的名称将包含在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; } }