更新
我已将此处的各种答案组合成一个新问题的“明确”答案。
原始问题
在我的代码中,我有一个事件发布者,它存在于应用程序的整个生命周期(这里简化为基本要素):
public class Publisher
{
//ValueEventArgs<T> inherits from EventArgs
public event EventHandler<ValueEventArgs<bool>> EnabledChanged;
}
因为这个发布者可以在任何地方使用,我很高兴自己创建了这个小助手类,以避免在所有订阅者中重写处理代码:
public static class Linker
{
public static void Link(Publisher publisher, Control subscriber)
{
publisher.EnabledChanged += (s, e) => subscriber.Enabled = e.Value;
}
//(Non-lambda version, if you're not comfortable with lambdas)
public static void Link(Publisher publisher, Control subscriber)
{
publisher.EnabledChanged +=
delegate(object sender, ValueEventArgs<bool> e)
{
subscriber.Enabled = e.Value;
};
}
}
它工作得很好,直到我们开始在较小的机器上使用它,当我开始偶尔:
System.ComponentModel.Win32Exception
Not enough storage is available to process this command
事实证明,代码中有一个地方是订阅者控件被动态创建、添加和从表单中删除的。鉴于我对垃圾收集等的深入了解(即直到昨天还没有),我从来没有想过要在我身后进行清理,因为在绝大多数情况下,订阅者也会在应用程序的整个生命周期内都存在。
我已经用Dustin Campbell 的 WeakEventHandler摆弄了一段时间,但它不适用于匿名代表(无论如何都不适合我)。
反正有这个问题吗?我真的很想避免在整个商店复制粘贴样板代码。
(哦,别问我为什么我们一直在创建和销毁控件,这不是我的设计决定......)
(PS:这是一个winforms应用程序,但我们已经升级到VS2008和.Net 3.5,我应该考虑使用弱事件模式吗?)
(PPS:来自 Rory 的好答案,但如果有人能想出一个与 WeakEventHandler 等效的方法,这样我就不必记住显式 UnLink/Dispose,那会很酷......)
编辑我必须承认我通过“回收”有问题的控件来解决这个问题。然而,解决方法又回来困扰我,因为我使用的“钥匙”显然不是唯一的(呜咽)。我刚刚在这里发现了其他链接(尝试过这个 - 似乎有点太弱了- 即使目标仍然存在,GC也会清除代表,下面的 s,oɔɯǝɹ 答案也有同样的问题),这里(强制你修改发布者,并且不't 真正与匿名代表一起工作)和这里(引用为不完整的达斯汀坎贝尔)。
我突然想到,我正在寻找的东西在语义上可能是不可能的——闭包的设计目的是“即使在我离开后也能闲逛”。
我找到了另一种解决方法,所以我会坚持下去,等待众神的声音。