【发布时间】:2010-09-27 03:11:04
【问题描述】:
更新
我已将此处的各种答案合并为new question 上的“确定”答案。
原始问题
在我的代码中,我有一个事件发布者,它在应用程序的整个生命周期都存在(这里简化为基本要素):
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's WeakEventHandler 摆弄了一段时间,但它不适用于匿名代表(反正不适合我)。
有没有解决这个问题?我真的很想避免在整个商店复制粘贴样板代码。
(哦,别问我为什么我们一直在创建和销毁控件,这不是我的设计决定......)
(PS:这是一个winforms应用,但是我们已经升级到VS2008和.Net 3.5,我应该考虑使用Weak Event pattern吗?)
(PPS:很好 answer from Rory,但如果有人能想出一个等效于 WeakEventHandler 的方法,这样我就不必记住显式 UnLink/Dispose 了,那就太好了...)
编辑我必须承认我通过“回收”有问题的控件来解决这个问题。然而,解决方法又回来困扰我,因为我使用的“钥匙”显然不是唯一的(呜咽)。我刚刚发现了其他链接here(试过这个 - 似乎有点太弱 - 即使目标仍然存在,GC也会清除代表,下面的s,oɔɯǝɹ answer也有同样的问题),@987654327 @(强制您修改发布者,并且实际上不适用于匿名代表)和 here(被 Dustin Campbell 引用为不完整)。
我突然想到,我正在寻找的东西在语义上可能是不可能的——闭包的设计目的是“即使在我离开后也能闲逛”。
我找到了另一种解决方法,所以我会坚持下去,等待voice from the gods。
【问题讨论】:
-
@Benjol 哇.. 很高兴看到另一个 lambda 怪胎 :-)
-
看看 Reactive 框架是否对这个问题有什么要说的会很有趣......
标签: c# event-handling garbage-collection