One Liner:WeakReference-to-a Lambda事件处理程序

时间:2010-07-15 21:24:24

标签: c# .net event-handling lambda weak-references

除了多次使用它会违反DRY原则这个事实之外,你能看到这个单行的缺点吗?这看起来很简单,但事实上我没有看到其他人提出这个问题让我想知道它是否有缺点。

这段代码为方法创建WeakReference,然后注册调用引用目标的事件处理程序。

SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)();

谢谢,

2 个答案:

答案 0 :(得分:12)

我不认为这种模式符合您的期望。您是否试图阻止事件持有对当前对象的引用以防止内存泄漏? lambda表达式将捕获this的值以便评估ProcessEvent(假设ProcessEvent是实例方法),因此您仍然会有泄漏。此代码与执行SomeEvent += (sender, e) => ProcessEvent();相同。

你可能会尝试做更像这样的事情(这也不是你想要的):

var reference = new WeakReference((Action)ProcessEvent);
SomeEvent += (sender, e) => ((Action)reference.Target)();

现在lambda表达式将捕获WeakReference,因此您不会强烈引用this。不幸的是,没有别的东西引用从ProcessEvent创建的委托,因此即使this仍然存在,它也会在下一个GC上删除。 (这也不会检查Target是否为null)。

您可以尝试这样的事情:

public EventHandler MakeWeakHandler(Action action, Action<EventHandler> remove)
{
    var reference = new WeakReference(action.Target);
    var method = action.Method;
    EventHandler handler = null;
    handler = delegate(object sender, EventArgs e)
    {
        var target = reference.Target;
        if (target != null)
        {
            method.Invoke(target, null);
        }
        else
        {
            remove(handler);
        }
    };
    return handler;
}

然后像这样使用它:

SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h);

这将保留对ProcessEvent的接收者的弱引用,并将在收集事件后自动从事件中删除事件处理程序,这可以防止内存泄漏,只要事件是定期引发的。

答案 1 :(得分:0)

它不太可读。如果你必须通过单步调试它,那么这些动作中的任何一个都可能失败,但是那一行会失败。此外,您只能在堆栈跟踪中引用该单行。

您通常希望避免在一行中执行太多操作以实现可维护性。