假设我有一个名为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();
}
用户可以在一天中将此对话框实例化数十次甚至数百次。
当作用域离开私有方法时,垃圾收集器是否会自动清除与对话框实例相关的所有内容,包括匿名侦听器的所有管道?
由于
答案 0 :(得分:2)
活动的发布者保留对每个订阅者的强烈引用。如果发布者的寿命比订阅者长,那么订阅者将在发布者出现时固定在内存中。
在您的示例中,发布者仅存在于私有方法的范围内,因此在方法返回后的某个时刻,对话框和处理程序都将被垃圾收集。
我建议遵守dot net framework guidelines for publishing an event,建议使用受保护的虚拟方法来调用事件。
答案 1 :(得分: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;
}
}