使用事件处理匿名委托时,垃圾收集 [英] Garbage collection when using anonymous delegates for event handling

查看:136
本文介绍了使用事件处理匿名委托时,垃圾收集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新

我已经联合从这里各种各样的回答到一个<一个一个明确的答案href=\"http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas/1747236#1747236\">new问题。

I have combined various answers from here into a 'definitive' answer on a new question.

原题

在我的code我有一个事件发布,它存在的应用程序(这里减少到最基本)的整个生命周期:

In my code I have an event publisher, which exists for the whole lifetime of the application (here reduced to bare essentials):

public class Publisher
{
    //ValueEventArgs<T> inherits from EventArgs
    public event EventHandler<ValueEventArgs<bool>> EnabledChanged; 
}

由于此发布者可以到处使用,我很高兴,因为创建这个小助手类,以避免重新编写处理code中的所有用户:

Because this publisher can be used all over the place, I was quite pleased with myself for creating this little helper class to avoid re-writing the handling code in all subscribers:

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

这工作得很好,直到我们开始使用它在更小的机器,当我开始偶尔的:

It worked fine, until we started using it on smaller machines, when I started getting the occasional:

System.ComponentModel.Win32Exception
Not enough storage is available to process this command

事实证明,没有在code,其中的用户控件被动态创建一个地方,添加和表格中删除。鉴于我的垃圾收集等先进的理解(即无,直到昨天),我从来没有想过要收拾我的身后,因为在绝大多数情况下,订户还生活应用程序的生命周期。

As it turns out, there is one place in the code where subscribers controls are being dynamically created, added and removed from a form. Given my advanced understanding of garbage collection etc (i.e. none, until yesterday), I never thought to clear up behind me, as in the vast majority of cases, the subscribers also live for the lifetime of the application.

我周围的<一个一阵拨弄href=\"http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx#commentstart\">Dustin坎贝尔的WeakEventHandler ,但它的不与匿名委托的(不适合我反正)工作。

I've fiddled around a while with Dustin Campbell's WeakEventHandler, but it doesn't work with anonymous delegates (not for me anyway).

反正是有解决这一问题的?我真的想以避免复制粘贴锅炉板code各地的商店。

Is there anyway out of this problem? I really would like to avoid having to copy-paste boiler-plate code all over the shop.

(呵呵,不问我,为什么我们正在创建和销毁控制所有的时间打扰,这不是我的设计决定...)

(Oh, and don't bother with asking me WHY we are creating and destroying controls all the time, it wasn't my design decision...)

(PS:这是一个WinForms应用程序,但我们已经升级到VS2008和.Net 3.5,我应该考虑使用的弱事件模式?)

(PS: It's a winforms application, but we've upgraded to VS2008 and .Net 3.5, should I consider using the Weak Event pattern?)

(PPS:从罗里好的答案,但如果有人能拿出一个相当于WeakEventHandler从而避免了我要记得显示断开链接/处置,这将是很酷...)

(PPS: Good answer from Rory, but if anyone can come up with an equivalent to the WeakEventHandler which avoids me having to remember to explicitly UnLink/Dispose, that would be cool...)

修改我必须承认,我工作围绕这一问题,通过再造问题的控制。然而,解决方法已经回来困扰我的'钥匙'我所用,显然非唯一(SOB)。我刚刚发现的其他链接这里(试过这 - 似乎是有点的的薄弱 - GC清除即使目标还活着,用<一个同样的问题,与会代表href=\"http://stackoverflow.com/questions/371109/garbage-collection-when-using-anonymous-delegates-for-event-handling/955928#955928\">s,oɔɯǝɹ回答下面),<一个href=\"http://$c$c.logos.com/blog/2008/08/event%5Fsubscription%5Fusing%5Fweak%5Freferences.html\">here (逼着你修改发布,并没有真正与匿名委托工作)和这里(引,如不完全由达斯汀·坎贝尔)。

EDIT I must admit that I worked around this problem by "recycling" the controls in question. However the workaround has come back to haunt me as the 'key' I was using is apparently non-unique (sob). I've just discovered other links here (tried this - seems to be a bit too weak - GC clears delegates even if target is still alive, same problem with s,oɔɯǝɹ answer below), here (forces you to modify publisher, and doesn't really work with anonymous delegates) and here (cited-as-incomplete by Dustin Campbell).

它发生,我认为我正在寻找可能在语义上是不可能的 - 封闭的设计流连我走了之后,连。

It occurs to me that what I'm looking for may be semantically impossible - closures are designed to 'hang around even after I'm gone'.

我找到了另一个解决办法,所以我会与坚守,以待神一个的声音。

I've found another workaround, so I'll stick with that, pending a voice from the gods.

推荐答案

我知道,这个问题是一个古老的,但地狱 - 我发现它,我估计别人不如。我试图解决相关的问题,并可能有一些见解。

I know that this question is ancient, but hell - I found it, and I figure that others might as well. I'm trying to resolve a related issue, and might have some insight.

您提到的达斯汀·坎贝尔WeakEventHandler - 它的确不能与设计匿名方法的工作。我试图拨弄起来的东西,会的,当我意识到一个)的情况下,99%我需要这样的他原来的解决方案的东西会更安全,和b)在这些少数情况下,我必须(注:已为,而不是想,因为lambda表达式是这么多的prettier,简洁),它可能使你得到一个小聪明它的工作。

You mentioned Dustin Campbell's WeakEventHandler - it indeed cannot work with anonymous methods by design. I was trying to fiddle something together that would, when I realized that a) in 99% of cases I'd need something like this his original solution would be safer, and b) in those few cases where I have to (note: have to, not "want to because lambdas are so much prettier and concise") it's possible to make it work if you get a little clever.

您的例子似乎正是那种在那里得到一个有点棘手,可能会导致一个相当简洁的解决方案一次性的情况。

Your example seems like exactly the kind of one-off case where getting a little tricky can result in a fairly concise solution.


public static class Linker {
    public static void Link(Publisher publisher, Control subscriber) {
        // anonymous method references the subscriber only through weak 
        // references,so its existance doesn't interfere with garbage collection
        var subscriber_weak_ref = new WeakReference(subscriber);

        // this instance variable will stay in memory as long as the  anonymous
        // method holds a reference to it we declare and initialize  it to 
        // reserve the memory (also,  compiler complains about uninitialized
        // variable otherwise)
        EventHandler<ValueEventArgs<bool>> handler = null;

        // when the handler is created it will grab references to the  local 
        // variables used within, keeping them in memory after the function 
        // scope ends
        handler = delegate(object sender, ValueEventArgs<bool> e) {
            var subscriber_strong_ref = subscriber_weak_ref.Target as Control;

            if (subscriber_strong_ref != null) 
                subscriber_strong_ref.Enabled = e.Value;
            else {
                // unsubscribing the delegate from within itself is risky, but
                // because only one instance exists and nobody else has a
                // reference to it we can do this
                ((Publisher)sender).EnabledChanged -= handler;

                // by assigning the original instance variable pointer to null
                // we make sure that nothing else references the anonymous
                // method and it can be collected. After this, the weak
                //  reference and the handler pointer itselfwill be eligible for
                // collection as well.
                handler = null; 
            }
        };

        publisher.EnabledChanged += handler;
    }
}

在WPF弱事件模式据传配备了一个很大的开销,所以在这种特定情况下,我不会使用它。此外,在一个WinForm程序引用核心WPF库似乎有点沉重的为好。

The WPF Weak Event pattern is rumored to come with a lot of overhead, so in this particular situation I wouldn't use it. Furthermore, referencing the core WPF library in a WinForm app seems a little heavy as well.

这篇关于使用事件处理匿名委托时,垃圾收集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆