为什么BackgroundWorker在调用委托的BeginInvoke时不需要调用EndInvoke?

3
这篇帖子说当你在委托上调用BeginInvoke方法时,始终需要调用EndInvoke方法。另一篇帖子支持这一说法,并建议使用类BackgroundWorker作为替代方案。
我使用ILSpy反编译了BackgroundWorker,发现实际上,即使它在委托上使用了BeginInvoke方法,但从未调用过EndInvoke方法。
这是否意味着BackgroundWorkder实现不良,或者说调用EndInvoke并不是那么必要?
(关于异常丢失的问题与此无关,因为整个被调用的方法被包含在try-catch块中)
在类似的问题上:有没有明确的理由解释为什么实现BackgroundWorker选择了BeginInvoke而不是ThreadPool.QueueUserWorkItem()
编辑:可以在此处查看BackgroundWorker的源代码here
1个回答

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用户,无法保证这个说法成立,但Microsoft这样做应该没问题。在源代码中添加一条注释会很好。


顺便说一句:我手头没有链接,但是我在大约十年前研究过这个问题,并记得找到了微软认可的参考资料,描述了委托和ControlEndInvoke()方法都是可选的。我对MSDN的参考资料感到惊讶,因为它显然与我早些时候发现的委托方案参考相矛盾(但似乎特定的参考资料至少在.NET 2.0之前就有了这个建议)。当然,如果您实际上想要接收调用的委托的返回值,调用EndInvoke()是很重要的。 :) - Peter Duniho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接