日期:2012-07-08  浏览次数:20396 次

Visual Basic .NET中的异常处理简介(上)

作者:Microsoft  
------------------------------------------------------------
  摘要:本文简单介绍了 Visual Basic .NET 中的结构化异常处理和非结构化异常处理。文中包括了各种注意事项,可帮助您选择正确的异常处理选项、各选项涉及的步骤、如何创建自己的异常以及异常对象的属性。最后在表中列出了预定义的异常类及其派生类。
  简介

  只有极其优秀的程序员才能一步到位地编写出完美的代码,其他程序员必须经过不断的修改才能开发出成功的应用程序。
  幸运的是,Microsoft? Visual Basic? .NET 提供了两种处理异常的方法。第一种是非结构化异常处理,它符合 Visual Basic 早期版本中的异常处理规则。第二种是结构化异常处理,类似于 Microsoft? Visual C#? 或 Microsoft? Visual C++? 中的异常处理方式。
  本文简单介绍了结构化异常处理和非结构化异常处理,面向的读者是 Visual Basic 初级开发人员,或者从 Visual Basic 早期版本转换到 Visual Basic .NET 的开发人员。文中包括了各种注意事项,可帮助您选择正确的异常处理选项、各选项涉及的步骤、如何创建自己的异常以及异常对象的属性。阅读本文后,您将了解如何以及何时在代码中加入异常处理。  “错误”和“异常”的定义
  术语“错误”和“异常”经常被混用。实际上,错误是指在执行代码过程中发生的事件,它中断或干扰代码的正常流程并创建异常对象。当错误中断流程时,该程序将尝试寻找异常处理程序(一段告诉程序如何对错误做出响应的代码),以帮助程序恢复流程。换句话说,错误是一个事件,而异常是该事件创建的对象。
  程序员使用短语“产生异常”时,表示存在问题的方法发生错误,并创建异常对象(包含该错误的信息及发生的时间和位置)来响应该错误。导致出现错误和随后异常的因素包括用户错误、资源失败和编程逻辑失败。这些错误与代码实现特定任务的方法有关,而与该任务的目的无关。
  针对本文的目的,“异常处理”的意思是解释和响应因错误而产生的异常。  结构化异常处理和非结构化异常处理 - 分别在什么情况下使用
  简单来说,结构化异常处理就是使用包含异常、单独的代码块和筛选器的控制结构创建异常处理机制。它使代码可以区分不同的错误类别,并根据相应的情况做出响应。在非结构化异常处理中,代码开始处的 On Error 语句将处理所有的异常。
  与非结构化异常处理相比,结构化异常处理更强大,更具普遍性和灵活性。如有可能,请尽量使用结构化异常处理。然而,在以下情况下可能需要使用非结构化异常处理:
升级使用 Visual Basic 早期版本编写的应用程序时。
开发应用程序的初期版本或草稿版本,而且,即使程序不能正常关闭您也不会介意。
事先已确切知道将导致出现异常的原因。
迫于截止日期而需要走捷径。
代码非常琐碎或者太短,只需要测试其中产生异常的代码部分。
需要使用 Resume Next 语句,而结构化异常处理不支持该语句。

  不能在同一个函数中将结构化异常处理和非结构化异常处理组合使用。如果使用了 On Error 语句,则不能在同一个函数中使用 Try...Catch 语句。
  不管在代码中使用哪种异常处理,都必须回退一步先检查代码假设的条件。例如,当应用程序要求用户输入电话号码时,以下假设开始起作用:
用户必须输入数字而不是字符。
输入的号码必须符合某种格式。
用户不能输入空字符串。
用户只能输入一个电话号码。

  用户的输入可能会不符合上述一条或全部假设。完善的代码需要足够的异常处理,以允许在违反上述假设的情况下恢复应用程序。
  除非能够确保您的方法在任何情况下都不会产生异常,否则请考虑使用信息性异常处理。异常处理应该直观。除了指出产生错误以外,异常处理产生的消息中还应指示错误产生的原因及其位置。诸如“发生错误”之类的毫无意义的消息只能使用户感到失望。
  

  结构化异常处理
  结构化异常处理测试特定的代码片段,并在发生异常时改编此异常处理代码,以适应导致该异常的环境。与非结构化异常处理相比,结构化异常处理在大程序中运行得较快,在响应错误时更具灵活性,且具有更高的应用程序可靠性。
  Try...Catch...Finally 控制结构是结构化异常处理的基本结构。它测试代码片段,筛选该代码执行过程中产生的异常,并根据产生的异常类型做出不同的响应。
  Try...Catch...Finally 块
  Try...Catch...Finally 控制结构测试代码片段,并指导应用程序如何处理各种不同类型的错误。在此过程中,该结构的三个组成部分分别扮演着特定的角色。
Try 语句提供正在测试异常的代码。
Catch 子句标识与特定异常相关联的代码块。Catch When 块指导代码在特定情况下执行。不包含 When 的 Catch 子句将响应所有异常。因此,代码中可能包含一系列特定的 Catch...When 语句,每条语句响应特定类型的异常,最后使用通用的 Catch 块来响应前面的 Catch...When 子句未能截取的任何异常。
不管 Try 块中是否发生异常,Finally 语句所包含的代码始终会执行。即使在 Exit Try 或 Exit Sub 语句后也会执行 Finally 语句。此代码通常执行清除任务,例如关闭文件或清除缓冲区。

  Catch 子句的用途
  Catch 子句可采用三种格式:Catch、Catch...As 和 Catch...When。
  不包含 When 关键字的 Catch 子句允许相关的语句块处理所有异常。Catch...As 和 Catch...When 子句捕捉特定的异常,并允许相关的语句块指导应用程序如何处理。也可以将 Catch...As 和 Catch...When 子句组合成一条语句,例如:Catch ex As Exception When intResult <> 0。
  如果异常是由资源失败引起的,该子句应该标识此资源,并在可能的情况下提供解决问题的建议或避免出现此问题的提示。如果异常是由编程逻辑失败引起的,该子句应该允许应用程序尽可能安全地退出。如果异常是由用户错误引起的,该子句应该允许用户更正错误并继续进行操作。
  Catch 子句按其在代码中出现的顺序执行。因此,当在整个代码序列中执行时,Catch 子句应该从特定部分移到通用部分。例如,在检查完类型后再检查其基本类型。处理 System.Exception 的 Catch 块应该放置到最后,在处理完所有其他可能的异常之后再执行。
Imports System
Try
  varAvailableSeats = varAuditoriumSeats - varNumberOfGuests
  Catch ex as Exception When varAuditoriumSeats = 0
  MsgBox("观众席没有座位!")
 Exit Sub
  Catch ex as Exception When varAvailableSeats < 0
  MsgBox("没有空余的座位。")
  Exit Sub
  Finally MsgBox("谢谢您对我们的音乐会感兴趣。")
End Try  

  Exception 对象
  Exception 对象提供所发生异常的有关信息。每次发生异常时,都将设置 Err 对象的属性,并创建一个新的 Exception 对象实例。查看其属性可以确定代码位置、类型以及异常的起因。
  以下是 Exception 对象的一些常用属性:
HelpLink 属性包含一个 URL,指导用户进一步查询该异常的有关信息。
Hresult 属性获取或设置分配给异常的数值 HRESULT。HRESULT 是一个 32 位数值,包含三个字段:严重性代码、设备代码和错误代码。严重性代码指示返回的值表示的是信息、警告还是错误。设备代码标识负责异常的系统区域。错误代码是分配给错误的唯一编号。
InnerException 属性返回一个异常对象,代表发生异常时正在处理的异常。处理外部异常的代码也许可以使用内部异常的信息,从而更准确地处理外部表达式。
Message 属性包含一个字符串,它是一些文本消息,告知用户错误的性质以及处理该错误的最佳方法。创建异常对象时,用户可以提供最适用于