在VB 2005中定制自己的异常


   构造化 异样 解决是随着.net的第一个版本的发行而加入到Visual Basic语言中的 。 构造化 异样 解决的主要性基于下面两个缘由:

   1. 与以往的On Error Goto...语句相比而言,通过 使用一种与该语言其它 部分更适应的语法从而使得代码更 存在可读性 。

   2. 比以往的On Error Goto...语句 性能更强,而且提供了更为灵便性的操纵 威力 。

   一、 拿获并抛出 异样

   异样 解决是用Try...Catch...Finally...End Try语句实现的,其 根本语法 模式如下:

Try

' 可以激发一个 异样的代码

Catch

' 解决 异样的代码

Finally

'实现清理工作的代码(如关闭数据库衔接,等等)

End Try

   Try和End Try语句都是 必须的 。Catch和Finally语句 可以一起 使用于一个Try块中,然而至少 使用其中之一 。而且, 可以 使用多个Catch语句来 解决不同类型的 异样 。假如你有多个Catch块, 可以对它们加以排序:从最具体的 异样类型到最粗略的 异样类型:

Try

  ' 可以激发一个 异样的代码

Catch ex As ArgumentOutOfRangeException

  '有可能 使用一个缺省值来 解决一个无效参数以便使代码 接续执行

Catch ex As Exception

  ' 解决任何其它类型的 异样

Finally

  '实现清理工作的代码(如关闭数据库衔接,等等)

End Try

   你也 可以在你的代码中抛出 异样 。当你在代码中执行一些清理工作时, 拿获并抛出 异样是很有用的-这样以来,一个更高层级的过程 可以 拿获它 。当你 缔造定制 异样类型时,抛出 异样也很有用 。

   为了抛出一个 异样,你 可以编写如下 模式的代码:

Throw New ArgumentOutOfRangeException

   ArgumentOutOfRangeException告诉Throw语句要抛出什么类型的 异样 。这个ArgumentOutOfRangeException类型仅是.NET框架所提供的很多的类型之一 。

   二、 流传 异样

   当一个 异样浮现于你的代码的某处时,你 可以以三种 模式 流传它:

   ·什么也不做而让它自动地 流传回调用栈(由系统自动 解决) 。

   · 拿获并再次抛出它 。这 可以同意你在Finally块中运行一些清理代码 。

   · 拿获它,并 使用InnerException属性在另一个 异样中包装该 异样,而且把这个新的 异样抛回调用过程 。这个InnerException属性 可以让你维持原始的 异样并在一个关系更为紧密的 异样中 存放它的信息

   三、 定制自己的 异样

   只管.net框架提供了许多 标准 异样,但你也 可以 缔造,抛出和 拿获你自己的定制 异样 。普通地,微软推举你 使用由.NET框架所提供的 标准 异样 。然而,假如你的 利用程序仅 使用一个 标准 异样不能满足需求时,你 可以 缔造一个定制 异样 。

   当你 缔造一个定制 异样类型时,你就能操纵全部的 异样属性 。你还 可以把属性增加到你的定制 异样类中 。除了把 要害数据嵌入到Message属性中外,这 可以使你有另外一个地方来存储这些数据 。而且,这 可以使得检索 要害数据十分 方便而 毋庸在Message属性外 综合它们 。

   四、 定制 异样示例

   为了 了解定制 异样,让我们 缔造一个很 方便的命令行 利用程序来加以具体 注明 。

   该代码包括一个十分 方便的仅含有一个表Customer的MS Access数据库 。丝毫也不奇怪,这个Customer表包括一组顾客记录( 存在CustomerID,first name,last name,address details共四个字段) 。该数据库的实际内容并不主要,然而,在你的定制 异样中实现数据存取是一种十分 合适的 取舍 。

   关于本 利用程序来说,我用VB 2005 Express IDE 缔造了一个新的操纵台 利用程序 。

   五、 DatabaseException基类

   假如你想 缔造多个定制 异样,那么为这些定制 异样 缔造一个定制基类是个不错的 主张 。这个基类将继承自.NET框架所提供的 System.Exception类 。它还包括三个 构造器-它们 几乎 可以 实用于全部你的定制 异样 。本文中示例 利用程序的基类称作 DatabaseException,其代码显示如下:

Public Class DatabaseException

Inherits Exception

Public Sub New()

End Sub

Public Sub New(ByVal message As String)

  MyBase.New(message)

End Sub

Public Sub New(ByVal message As String, ByVal inner As Exception)

  MyBase.New(message, inner)

End Sub

End Class

   这三个 构造器都是System.Exception类提供的 标准的 构造器 。第一个同意你 缔造一个 异样而 毋庸 使用任何参数-仅需求缺省的 异样属性即可 。第二个同意你指定一个 信息串以用作你的 异样的Message属性 。最终,第三个 构造器也同意你指定一个 信息串,然而它同意你指定一个 异样作为第二个参数 。 System.Exception类有一个属性InnerException-当你 拿获一个 异样并想把它包装到一个关系更相近的 异样的内部时,这个属性很有用 。通过设置InnerException属性,你 可以维持在原始 异样中的全部信息 。

   有关基类最终丝毫要 留神的是,在从 System.Exception类继承还是从System.ApplicationExeption类继承的问题上开发者们的意见并不 统一 。大多数的微软老消费者认为你应该从System.ApplicationException继承,然而也有一些开发者认为应该从System.Exception类继承 。我也不确定是不是它们中间存在什么技术差距,然而,我对这两种状况均作过测试,它们都 可以 畸形工作 。关于本文示例 利用程序,我们 使用了后面的 思维-从 System.Exception类中继承 。

   六、 定制 异样:CustomerNotFoundException

   第一个定制 异样类是CustomerNotFoundException 。当你试图在你的数据库中搜索一个客户但未找到相应的匹配时你会抛出这个 异样 。实现代码如下所示:

Public Class CustomerNotFoundException

Inherits DatabaseException

Private m_CustomerID As Long

Public ReadOnly Property CustomerID() As Long

Get

  Return m_CustomerID

End Get

End Property

Public Sub New(ByVal customerID As Long)

  MyBase.New("Customer ID was not found.")

  m_CustomerID = customerID

End Sub

End Class

   这个类继承自你前面所 缔造的DatabaseException基类 。它仅包括一个 构造器--其参数为customerID 。当调用这个 构造器时,你把文本串"Customer ID was not found."传递到基类的 构造器以用作Message属性 。你还有一个已定义的只读属性CustomerID 。你将 使用这个CustomerID属性来存储要被作为一个参数传递的CustomerID的值 。它是一个只读属性,由于把这个值转变为除了激发 异样的值以外的值并没有什么 意思 。

   七、 定制 异样-DatabaseUnavailableException

   第二个定制 异样类是DatabaseUnavailableException 。当你想衔接到一个数据库并 产生一个 异样时,你就抛出这个 异样 。其实现代码如下:

Public Class DatabaseUnavailableException

Inherits DatabaseException

Public Sub New(ByVal ex As Exception)

  MyBase.New("The database is not available.", ex)

End Sub

End Class

   这个类十分 类似于你的CustomerNotFoundException类 。你不用为这个类定义任何其它属性,然而它们的主要区别在于,它把一个 System.Exception作为一个参数而且把它传递到你的基类的 构造器中 。这个System.Exception参数将成为你的 DatabaseUnavailableException的InnerException属性 。

   八、 Customer类

   Customer类是一个 方便类,这个类的 构造器 使用一个数据库名和一个CustomerID作为参数而且负责检索该顾客相应的数据 。该 构造器要做的第一件 事件是,通过 使用ConnectDB 步骤尝试 构建到数据库的衔接 。具体代码如下:

Private Sub ConnectDB(ByVal database As String, _

  ByRef cn As OleDbConnection)

  cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; _

  Data Source=" & _

"""" & database & """"

  Try

   cn.Open()

  Catch ex As Exception

   Throw New DatabaseUnavailableException(ex)

  End Try

End Sub

   你试图在一个Try语句内 打开数据库衔接 。假如抛出任何 异样的话,你就会 拿获它并抛出一个DatabaseUnavailableException-这个 异样用它的InnerException属性包装了原始的 异样 。

   假如你 顺利地衔接到数据库,那么你就试图 使用GetCustomer 步骤来检索相应于指定CustomerID的数据,详见下面的代码:

Private Sub GetCustomerData(ByVal cn As OleDbConnection, _

  ByVal customerID As Long)

  Dim cmd As New OleDbCommand

  Dim reader As OleDbDataReader

  cmd.Connection = cn

  cmd.CommandText = "SELECT * FROM CUSTOMER WHERE ID = " _

& customerID

  reader = cmd.ExecuteReader

  If reader.HasRows Then

   reader.Read()

   m_id = reader.Item("ID")

   m_firstname = reader.Item("Firstname")

   m_lastName = reader.Item("Lastname")

   m_street = reader.Item("Street")

   m_city = reader.Item("City")

   m_state = reader.Item("State")

   m_zipCode = reader.Item("Zip")

  Else

   Throw New CustomerNotFoundException(customerID)

  End If

End Sub

   上面的代码中,你执行了一个SQL 查问--其中 使用CustomerID来指定你想要检索哪个顾客的数据 。假如 查问返回一个 后果,那么你 使用从该 查问返回的值设置Customer类的属性 。然而,假如你没有得到任何值的话,你将 使用customerID作为 构造器的参数抛出一个 CustomerNotFoundException 异样 。这个值将用于设置你的CustomerNotFoundException对象的 CustomerID属性 。

   九、 总结

   定制 异样类型是VB.net语言中的一个十分有力的 特色 。.NET框架提供了许多 标准的 异样类型,关于大多数 利用而言,已经足够了 。事实上,你可能会很少用到 标准 异样之外的东西;然而,特别状况下定制自己的 异样会 普及你的 利用程序的茁壮性 。