阻止开发人员调用System.Windows.Forms.Application.DoEvents()的最佳方法是什么?

我们花了300个工时来修复现场的一个错误的应用程序。 这一切都归结为调用Application.DoEvents(re-entrancy problem)。

这没有在设计评论,代码评论中发现。 代码是两年前插入的第一个版本; 应用程序总是“不稳定”,但最近的变化在很大程度上暴露了重新入侵问题。

此事件是我们组织中第二次发生Application.DoEvents导致失败和多人工作时间的调试。 在这种情况下,通过简单地注意到调用,在一个异步任务的复杂事件处理程序中埋下来,就发现了它。

你有什么建议可以防止这个问题再次发生:

  • 添加签入门到源代码管理?
  • 开发者培训?
  • 代码分析规则(为什么这不是内置规则?)

如何执行编码练习?

每次集中构建应用程序时,在每个程序集上运行它:

ildasm MyAssembly.exe /TEXT 

然后搜索输出:

 System.Windows.Forms.Application::DoEvents 

如果找到,请将构建标记为失败,就好像它是编译错误一样。

维护开发标准并将其添加到其中。

上述所有的。 在你期望任何成功的机会之前,你需要教会人们规则。 您可能还想告诉别人,为什么规则很重要。

遵循那些阻止你违反规则的工具总是一个好主意。 您的具体问题可能是FxCop规则或登记政策的地址。

相关问题: 你有编码标准吗? 如果是这样,他们是如何执行的?

防止这种情况的更有效方法是编写一个标记此API用法的FxCop规则。 如果在构建过程中启用了FxCop,则会在尽可能早的时间内将其消除

我建议对异步编程进行一些培训(使用BeginInvoke),并在另一个线程的后台执行耗时的任务。

除了试图阻止使用调用之外,有一种方法可以使它更容易发现这样的问题(以及其他问题):

在代码中使用大量ASSERT。

我的应用程序( MSQuant )中有一个类似的问题与DoEvents()和re-entrancy。 但是在我自己的测试期间,它被ASSERT提前捕获,从未影响任何用户。

ASSERT很早就发现了错误,我节省了很多很多小时的调试时间。 此外,他们可能会捕获否则会被忽视的错误(例如产生不正确的结果)。

这是一种非常有效的练习(高奖励率)。 我很多年前就已经了解它并且从那时起就开始使用它。 当然,它并不能取代其他做法:合理的软件工程,unit testing,代码标准,验收测试,代码检查。

请注意,触发ASSERT可能不一定会导致ASSERT对话框(停止正常执行或停止用户工作)或中止程序。 它可以配置为通过网络等将信息发送到日志记录系统(例如,文件)。

“我们只花了300个工时来修复现场的一个错误的应用程序。这一切都归结为调用Application.DoEvents(重新入侵问题)。”

首先让我说我并不是主张将Application.DoEvents用于临时使用,而是将x为long = 0写入long.maxvalue循环而没有一个,并看看UI的响应性如何。

如果不知道究竟发生了什么,很难说它是否真的是问题。

 Private Sub foo() stpw.Reset() : stpw.Start() Do Loop While stpw.ElapsedMilliseconds < 1000 stpw.Stop() Debug.WriteLine("foo") End Sub Dim stpw As New Stopwatch Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click Debug.WriteLine("") Debug.WriteLine("but click") Dim t As New Threading.Thread(AddressOf foo) t.Start() Do Threading.Thread.Sleep(10) 'Application.DoEvents() 'uncomment to change the behavior Loop While stpw.IsRunning Debug.WriteLine("but exit") End Sub 

因此,假设我最初在没有违规声明的情况下编写它,但是用户抱怨UI没有响应。 所以我然后添加DoEvents,但是当用户双击按钮时,我现在得到奇怪的结果。 是问题DoEvents还是只是糟糕的设计。 在这种情况下,我会投票给糟糕的设计。

缺少DoEvents是否会产生这个“好”的代码?

 Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click 'simulate a long running task For x As Long = 1 To Long.MaxValue - 1 'the absence of Application.DoEvents() is poor design IMHO Next End Sub