从 VB6 On Error 过渡到 .Net Try...Catch

Transitioning from VB6 On Error to .Net Try...Catch

我们公司最近从 VB6 过渡到 VB.NET。不幸的是,所有的错误处理仍然是 On Error GoTo。这使得追踪客户发回给技术支持的错误变得不容易。截至目前,On Error 包围的代码块是整个子例程,一个子例程有数百行代码并可能调用其他例程的情况并不少见。我的问题是如何最好地转换为 Try...Catch 块。我想我可以用 On Error GoTo Errorline 代替 try,用 Errorline 代替 catch。但这对于一个 try...catch 块来说似乎太多了。

VB6 与 error-handling 的最大弱点是运行时没有为您的代码提供获取执行堆栈的方法(方法 A 调用方法 B 调用方法 C,等等)发生异常时;即使您的 On Error 块捕获了异常,您的代码也不知道 "where it is"。为了解决这个缺陷,VB6 程序员学会了在每个模块中用 catch-all On Error 块封装每个方法,有时这样他们自己的代码就可以跟踪执行情况用于记录目的的堆栈。甚至有 third-party 工具可用于使用 On Error 块检测您的代码,正是为了这个目的(VB/Rig、VB-Failsafe)。

然而,

.Net 的 Exception 对象确实提供了 .StackTrack 属性 表示执行堆栈到故障点,因此不再需要使用 On Error 块在每个方法中,这样你就可以了解你的代码在哪里失败,post-mortem.

这是您在过渡时可以使用的一种简单策略:

首先,按照您的建议,将所有 "boilerplate" On Error Goto Errorline / :Errorline 替换为 Try / Catch ex As Exception 块。但是,仅在执行可以 "begin" 的 "top-level" 方法中执行此操作。在 VB 中,这些通常是表单中直接处理系统事件的所有事件方法(_Click_MouseDown_Timer 等)

其次,删除 "lower-level" 方法中的所有样板错误处理 -- 仅从 "top-level" 或其他 "lower-level" 方法中调用的方法。

现在您已经提供了 "safety net" 的 Try/Catch 异常处理,这将保护您的应用程序免于死于未处理的异常。当确实发生异常时,即使在执行堆栈的深处,您的代码将展开回最近的 Catch,通常是您的 UI event-handler 方法之一。但是,您将拥有 ex.StackTrack 属性 记录执行直至失败,一个模块一个模块,一个方法一个方法,每个级别都有源代码 line-number。

上述策略的一个例外是,当您发现一个 error-handling 块是 而不是 样板时——它是专门为处理特定错误而编写,并专门作出回应。保留此代码,但再次将 On Error Goto Errorline / :Errorline 替换为 Try / Catch ex As Exception.

这里有一个有用的经验法则:在您的 "top-level" 方法中,将整个方法包含在 "boilerplate" Try/Catch 中。在您的 "lower-level" 方法中,只在您可以 预期 某些异常会发生的代码周围编写 Try/Catch 块 --您的代码想要专门响应的那些。

Try/Catch 块包含大块代码并非不合理,或者 "too much"。您应该始终努力使您的方法尽可能短,但是没有理由仅仅因为它被 Try/Catch.

括起来就任意截断或分割一个长方法。