绕过 InvokeRequired,无需复制粘贴






4.93/5 (13投票s)
2007年8月17日
2分钟阅读

133882

768
与其在每个多线程函数中复制和粘贴相同的 if(InvokeRequired) 逻辑,不如使用特性来使代码更简洁,集中逻辑并使其具有自文档性。
引言
这或多或少是 Roy Osherove 的文章这里的重新发布。 这是一种向每个通常使用 if(InvokeRequired)
模式的函数添加属性 [RunInUIThread]
的方法。 我一直在寻找一种方法,不必将相同的代码复制并粘贴到所有需要多线程功能的函数中。 我偶然发现了 Roy 的文章,并认为这是自切片面包以来最好的东西。 我认为 Microsoft 应该将其构建到下一个 .NET 版本中,作为一种标准语言特性,因此我正在努力传播它。 告诉你的朋友,尤其是如果你的朋友在 Microsoft 工作。
我添加的唯一东西是单元测试。 这些演示了需要 InvokeRequired
,显示了手动解决方案,然后是使用属性改进的解决方案。 您需要 NUnit 2.4 才能运行单元测试。 技术示例很好,但是测试给了我一种温暖而柔和的感觉。
背景
附件中的示例使用了一种名为 AOP 的技术,即面向切面编程。 在不涉及所有相关术语的情况下,考虑此示例的最简单方法是 AOP 为我们提供了方法拦截功能。 因此,如果我们可以将属性放在一个函数上,我们可以将可以在特定函数之前和之后触发的方法关联起来。 在这些函数中,如果已指定该属性,我们可以检查是否需要使用 InvokeRequired
等。 此示例的 AOP 部分 Roy 是从 Castle Project 获取的。 有关更多详细信息,请参见链接。
Using the Code
public delegate void DoThreadedGoodManualType();
/// <summary>
/// This is good behavior, but this manual invoke required junk to be
/// done every time
/// </summary>
private void DoThreadedGoodManual()
{
if (this.InvokeRequired)
{
// Pass the same function to BeginInvoke, but the call would come on
// the correct thread and InvokeRequired will be false.
this.BeginInvoke(new DoThreadedGoodManualType(DoThreadedGoodManual));
return;
}
DoThreadedBad(); //now we can do our normal functionality with no worries
}
处理 WinForm 应用程序中多线程操作的通常接受的方式如上所示。 这很好用,但是缺点是您正在重复 InvokeRequired
代码,并且还必须创建委托。 如果,我们可以这样做呢?
[RunInUIThread]
protected virtual void DoThreadedGoodAOP()
{
DoThreadedBad();
}
啊,真奢侈。 好吧,现在你可以了!
关注点
我尝试测试代码时遇到了很多问题,因为消息泵送是由 WinForms 中的 application.run
完成的,这是 InvokeRequried
工作所必需的。 我徒劳地尝试通过在单独的线程上仅调用控件来使测试运行,但是,您需要实际的表单才能看到它的运行情况。 因此,单元测试有些非常规,因为它实际上是在启动 WinForm,并且 WinForm 正在引发一个事件,告知测试如果 InvokeRequired
为 true
或 false
,则 WinForm 会立即关闭自身,因此它不会只是坐在那里。 如果有人能想到更好的方法,我想看看!
记住查看 Roy Osherove 的博客。
历史
- 2007年8月16日 - 初始版本