【问题标题】:Why does BackgroundWorker not need to call EndInvoke when it calls BeginInvoke on a delegate?为什么BackgroundWorker在委托上调用BeginInvoke时不需要调用EndInvoke?
【发布时间】:2015-02-20 23:00:04
【问题描述】:

这个post 表示当您在委托上调用BeginInvoke 方法时,总是需要调用EndInvoke 方法。另一个 post 支持它并建议使用 BackgroundWorker 类作为替代方案。

我使用 ILSpy 对 BackgroundWorker 进行了反编译,我发现实际上,EndInvoke 在这个类中从不被调用,即使它确实在委托上使用了 BeginInvoke。 p>

这是否意味着BackgroundWorkder 没有实现,或者调用EndInvoke 根本没有必要?

(异常丢失的问题无关紧要,因为被调用的整个方法都包含在 try-catch 块中)

在类似的问题上:有一个明确的原因为什么在BackgroundWorker 的实现中选择BeginInvoke 而不是ThreadPool.QueueUserWorkItem()

编辑:BackgroundWorker的源代码可以查看here

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    我在幕后找了一会儿。 CLR 拥有 SynchronizationContext 类的秘密知识,因此从技术上讲,它可以在这里涉及。一无所获。

    在我首先检查我应该做的事情之前,实际验证需要 EndInvoke() 的声明:

    using System;
    
    class Program {
        static void Main(string[] args) {
            Action d = null;
            d = new Action(() => {
                d.BeginInvoke(null, null);
            });
            d();
            Console.ReadLine();
        }
    }
    

    跑得像大炮一样,消耗大量手柄。但它不会爆炸,它们永远不会超过 ~2000 并且内存使用量完全稳定。

    因此,调整需要调用委托的 EndInvoke() 的声明也许是合适的。如果您事先知道委托目标不会做任何不寻常的事情,例如调用另一个 AppDomain、运行本机代码或激活远程代码,那么您可以不调用 EndInvoke()。 BackgroundWorker 可以提供的保证。作为一个单纯的 SO 用户,我永远无法坚持这种说法。但是微软这样做了,所以它一定没问题。源代码中的注释会很好。

    【讨论】:

    • FWIW:我手边没有链接,但我在大约十年前研究了这个问题,并记得找到 Microsoft 认可的描述代表和 ControlEndInvoke() 的参考资料方法作为可选。我对 MSDN 参考感到惊讶,该参考至少与我之前发现的委托方案参考相矛盾(但似乎特定参考早在 .NET 2.0 就有该建议)。当然,如果您真的想接收被调用委托的返回值,那么调用EndInvoke() 很重要,所以就是这样。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    相关资源
    最近更新 更多