|
Page Options Life Without On Error Goto Statements Deborah Kurata InStep Technologies, Inc July 11, 2003 Summary: In previous versions of Visual Basic, the best practice for handling errors was put On Error Goto in every routine, but there is no On Error statement in Visual Basic .NET. This article describes how to use new Visual Basic .NET features to handle errors without using On Error Goto statements. (8 printed pages) 概述:在旧版本的Visual Basic 中,检测错误的最好方式是在每段程序中设置 On Error Goto 语句,但在VB.Net 中这个语句已经不能使用了。这篇文章正是讲述如何在VB.Net中通过 On Error Goto 以外的方法处理错误。(共8页)
Introduction 简介
This is the second in a series of articles that describe the fundamental changes in Visual Basic® and how to do today with Visual Basic .Net what you used to do in prior versions of Visual Basic. The first article covered life without control arrays. This article looks at how to implement error handling in your application without using On Error Goto statements. 这是第二次在一连串的文章中讲述假如你过去是一个 VB 程序员的话,过渡到VB.Net 之后需要经历怎样的基础性转变。The first article covered life without control arrays.而这一次我要讲讲怎样使用 On Error Goto 以外的方法处理程序错误。 There are three types of errors that can occur in your application: 在你的程序中,有三种错误会发生。
1.Anticipated errors: These are errors that your application can anticipate, such as attempting to read a file that does not exist or attempting to open a connection with an invalid connection string.
2.Unanticipated errors: These are errors that occur in your application due to unexpected conditions, such as a programming or data error.
3.Business rule violations: These could be data entry errors, such as the user entering alpha characters into a numeric field, or they could be more complex business logic issues, such as attempting to delete an order line item for an order that has already been shipped.
1、可以预测的错误:这种错误往往是可以预知的,例如试图去打开一个不存在的文件,或者试图去打开一个使用无效的 connection string 的连接。 2、不可预测的错我:这种错误在不能预见的条件下发生,例如程序和数据的错误。 3、违反业务规范的错误:这类可能是数据录入的错误,就像把一个希腊字符输入一个数值型的字段中;更或者,所犯的错误违背了业务上的某些准则,比方说试图去删除一个已经发货的订单。
The original versions of Visual Basic provided On Error Goto for catching and handling of any errors in your application. For anticipated errors, the On Error Goto could catch the error and then your code could attempt to recover. For unanticipated errors, the On Error Goto could catch the error and then your code could terminate gracefully, without the user seeing a system error message. For business rule violations, your code could raise a specific error number and then the On Error Goto statement could catch the error and display a user-friendly message. 旧版本的VB使用 On Error Goto 对付程序中的所有错误。对于可以预测的错误,On Error Goto 捕获到错误后可以通过修改代码去排除。对于不能预测的错误,On Error Goto 捕捉到后会终止你的代码继续执行。但对于违反业务规范的错误,On Error Goto 就不能很好的捕捉并可能因此造成巨大的错误后还返回一个友好的界面。
However, On Error Goto had some limits. Its goto style syntax made your routines structurally complex. And if you did not remember to exit the routine before the error handling at the bottom, it was easy to accidentally fall through the code into the error handling. It was difficult to have clean up code that ran in all cases (regardless of whether or not an error occurred). 然而,On Error Goto 的能力是有限的,但使用 goto 语句往往使你的程序变得复杂,如果你忘记了在程序的最后留出出口,这样会使程序的流程运行出乎意料之外。这时,清除所有错误的代码就显得困难。(至少要看错误是否发生了)
Visual Basic .NET has a rich set of features that provide all of the features of On Error Goto, without the limitations. VB.Net 对On Error Goto 提供了丰富的支持后,排除了他的局限性。 Note Actually, Visual Basic .NET does support On Error Goto through the Microsoft Visual Basic .NET Compatibility library. This library allows you to retain some of the Visual Basic 6.0 features in Visual Basic .NET to simplify the migration process. Features of this library should be used only for migration. 提醒:事实上,VB.Net 的MSVB.Net 兼容库不支持 On Error Goto ,这个兼容库主要是延续某些 VB6 的特性,使对VB.Net的移植更简单。这个对象库仅仅是为了移植使用。
Catching Exceptions 捕获异常
In .NET terms, errors are no longer called errors, but rather exceptions. Anticipated errors, unanticipated errors, and business rule violations are all considered to be exceptions. 在.Net的术语中,“错误”通常被称为“异常”,无论是可预见的错误、不可预见的错误,违反业务流程的错误,都称作异常。
After writing any routine, it is always a good idea to think about the exceptions that the routine could cause (anticipated errors), any unexpected exceptions that the routine could generate (unanticipated errors), and any business rules that the routine could violate. 当程序完成后,应当养成良好的习惯,思考程序可能出现的错误(即可预见错误),还有哪些不能估计的错误(不可预见错误)或者尽可能找出程序中与业务需求原则相违背的部分。
For example, many applications use a login form or page to control access to the application and its functions. The code to validate the login is executed when the user clicks on the login button as follows: 例如,很多程序会使用一个登录窗口获得用户信息去控制软件开放的功能,登录过程在用户按下[login]按钮时引发如下代码:
Private Sub cmdLogin_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles cmdLogin.Click Dim oUser As User() Dim bValid as Boolean oUser = New User() bValid = oUser.ValidateLogin(txtUserName.Text, txtPassword.Text) If bValid then DialogResult = DialogResult.OK End If oUser.Dispose oUser = Nothing End Sub
This code creates a new instance of the User class and then calls its ValidateLogin method to access the database and validate the user-entered username and password. If the login is valid, it sets DialogResult to OK to close the login form. It then disposes of the User class instance and returns. 代码创建了一个User类的实体并调用 ValidateLogin 方法连接数据库以验证用户的身份。如果用户合法,把“OK”附给 DialogResult 并清除User类的和其实体最后返回。
There are several places in this code that an exception could occur. The line of code that creates the new instance from the User class could generate an unanticipated exception if the instance cannot be created for some reason. The ValidateLogin method could generate anticipated exceptions (such as an invalid connection string), unanticipated exceptions (such as a missing table field or stored procedure), or business rule violations (such as passing an empty user name). 这样的代码会产生一些异常。如果User 类的实体因某些意外原因不能创建。ValidateLogin 方法也可以产生可预见的错误(例如数据库连接的失败),和不可预见的错误(比方说不能找到对应的字段和存储过程),甚至业务流程错误(用户输入了一个空的用户名)
Instead of adding an On Error Goto to catch these exceptions, the exceptions can be caught using a .NET Try/Catch block. The Try/Catch syntax makes it easier to catch and process exceptions in a structured manner; hence the reason that .NET exception handling is often referred to as structured exception handling (SEH). 在.Net中使用Try/Catch 模块,代替 On Error Goto 去捕获这些异常。Try/Catch 通过一个结构体,能更容易捕获和处以异常;因此,.Net通常用异常处以结构(SEH)去处理异常。
A Try/Catch block could be added to the code as follows: 一个 Try/Catch 模块可以添加到代码中:
Private Sub cmdLogin_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles cmdLogin.Click Dim oUser As User() Dim bValid as Boolean Try oUser = New User() bValid = oUser.ValidateLogin(txtUserName.Text, txtPassword.Text) If bValid then DialogResult = DialogResult.OK End If oUser.Dispose oUser = Nothing Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub
If any exception occurs in the Try block, the Catch block picks up the exception and the code within the Catch block will execute. In this case, the catch will grab any exception, assign the exception to the ex variable, and display a message box containing the exception message. If no exception occurs, the Catch block code is ignored. 如果一个异常发生在 Try 模块中,Catch 模块可以和提取异常并执行 Catch 后面的代码。在这个例子中,Catch模块可以提取异常,并把异常附给 ex 变量,显示一条包含错误内容的信息。如果没有异常发生,Catch 模块将被略过。
If you look closely at the example above, you will notice that the code to dispose of the instance won''''t be executed if an exception occurs. To correct this, the code could be repeated in the Catch block, but that means duplicating code. A better approach would be to use the optional Finally block within the Try/Catch block as follows: 如果你认真看上面的代码,你会发现如果异常发生了,实体的清除操作将不会发生。要解决这个问题,清除实体的代码又要添加到 Catch 模块中,这样会造成重复的代码。
Private Sub cmdLogin_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles cmdLogin.Click Dim oUser As User() Dim bValid as Boolean Try oUser = New User() bValid = oUser.ValidateLogin(txtUserName.Text, txtPassword.Text) If bValid then DialogResult = DialogResult.OK End If Catch ex As Exception MessageBox.Show(ex.Message) Finally oUser.Dispose() oUser = Nothing End Try End Sub
The code in the Finally block will be executed after the Try block completes successfully, after the Catch block executes, or after any Return statements are executed in the Try or Catch blocks. Any code that needs to be executed before leaving the routine should be added to the Finally block. Notice how the declaration of the User object was done outside of the Try block. This is required if the object variable will be accessible both from the Try block and the Finally block because .NET has block-scoped variables. Finally 模块会在 Try 模块成功后,Catch执行后,或者Reture 语句结束后启动。所有在结束程序前需要执行的事务都可以添加到 Finally 模块。然而在 Try 模块之前声明 User 对象,是应为该对象作为模块级的变量要在 Try和Finally中共同使用。
In prior version of Visual Basic, there were three types of variable scoping: 在早期的VB中,有以下三种变 [1] [2] [3] 下一页 |