VB.net学习笔记(十八)异常处理

前端之家收集整理的这篇文章主要介绍了VB.net学习笔记(十八)异常处理前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。




一、异常

.Net Framework处理的是异常而不是错误。因此不再会有“错误处理”。

.Net的公共语言库并不生成 错误代码。CLR创建一个称为异常的特殊对象,该对象的属性方法详细描述了异常情况以及

引起错误的具体原因


vb.net中新功能:历史调试,又称“黑盒记录器”。它允许测试人员在运行期间捕获当前状态信息。


尽管VB6中有On Error Goto,Resume、Err等,但强烈建议使用.Net内置的异常处理功能替代旧式语法

关于结构化异常处理与非结构化异常处理的区别参看:

http://blog.csdn.net/dzweather/article/details/10726115







二、.Net中异常处理


异常产生的实例(异常对象)是派生于System.Exception类的一个实例。

System.Exception有许多子类用于不同的情形 ,可以提供不同类型的异常信息。


异常对象常用的属性

HelpLink 一个表示异常的帮助链接的字符串(常为程序员自定义链接

InnerException 返回一个引用内部(嵌套)异常的异常对象。(后面会详述)

Message 包含错误的字符串,适合于显示用户

Source 一个包含生成错误的对象名称的字符串

StackTrace 只读属性,以文字字符串形式保存堆栈跟踪。

例:方法A调用方法B,且在B中发生异常,则堆栈跟踪就包含方法A与B

TargetSite 只读属性,用于保存抛出异常的方法(字符串形式)



异常对象常用的方法

GetBaseException 返回异常链接中的第一个异常

ToString 返回错误字符串,其中可能包含错误消息、内部异常以及堆栈跟踪等与错误有关的信息。









三、异常种类

.Net中有许多派生于Exception基类的异常对象,每个异常对象都适用于特定类型的异常。

异常有多种,不同的名称空间有不同功能的异常类。比如:

空间 类 描述

System InvalidOperationException 对象所处的状态不允许调用当前的对象方法时产生

System OutOfMemoryException 当没有足够的内存继续工作时产生

System.XML XmlException 尝试读无效的XML文件时产生

System.Data DataException 代表ADO.net组件产生的错误









四、Try....Catch 关键字

Try           '可能发生错误代码块
    [ tryStatements ]
    [ Exit Try ]   
[ Catch [ exception [ As type ] ] [ When expression ] '捕捉
    [ catchStatements ]
    [ Exit Try ] ]
[ Catch ... ]
[ Finally               
    [ finallyStatements ] ]    '最后处理
End Try

Try 用于可能出现错误代码

Catch 用于异常处理,当发生异常会出现在此处。

如果后面有 When则表示有异常且When句为真是进入

Finally 无论是否有异常,均进入此块


Catch可以有多个,发生异常时会逐个比较,只有当其中一个符合时,就进入此块,且后面的Catch不再进入。

注意:上面返回的是5,最后value的值是6,原因在于退出Try时,都会执行Finally,除非它是用End进行结束的。


下面演示多个Catch,它会依次向下比较,只有符合时就进入该块,进入后,后面的Catch块不再进入。

Public Class Form1
    Private Sub Button1_Click(sender As Object,e As EventArgs) Handles Button1.Click
        Dim i As Int32 = 4
        Dim j As Int32 = 0
        TextBox1.Text = GetTry(i,j)
    End Sub

    Private Function GetTry(ByVal a As Int32,ByVal b As Int32) As Int32
        Dim c As Int32

        Try
            c = a \ b
            Return c
        Catch ex As DivideByZeroException  '执行这个捕获,下个不执行
            MessageBox.Show("first")
        Catch ex As Exception
            MessageBox.Show("second")
        End Try

        Return c
    End Function
End Class








五、Throw 关键字

Catch并不能处理所有错误,因为有些异常无法预料。

为了把这个“无法预料”的异常捕捉到,可人为地抛出这样的异常,Throw就用于人为抛出这样的异常。


同异常一样,用了Throw,它后面的代码不再执行,因为异常会中断它们,要么被Catch捕捉,要么程序中断。

同前面一样,Throw也不能阻止Finally块的执行,即:在退出Try时仍然会执行Finally

Public Class Form1

    Private Sub Button1_Click(sender As Object,e As EventArgs) Handles Button1.Click
        Dim sngAvg As Single
        TextBox1.Text = GetAverage(0,100)
    End Sub
    Private Function GetAverage(iItems As Int32,iTotal As Int32) As Single
        Try
            Dim sngAverage As Single
            sngAverage = CSng(iTotal \ iItems)
            MessageBox.Show("sucessful")
            Return sngAverage
        Catch exD As DivideByZeroException
            MessageBox.Show("zero exception")
            Throw exD  '抛出异常,将结束整个捕获过程。此处会异常,因不再有捕获,程序会直接中断
            MessageBox.Show("More throw,but never executed")
        Catch exG As Exception
            MessageBox.Show("generic exception")
            Throw exG
        Finally
            MessageBox.Show("last step")
        End Try
    End Function

End Class

注意: 上面Throw不会再被捕捉,因为Catch只会捕捉同级别的Try内容

除非在Catch中再嵌套Try,并将Throw置于子Try中

Throw还可用于抛出自己创建的异常对象。

因此可以定制自己的异常消息。如下,异常消息改为自己的:

Public Class Form1

    Private Sub Button1_Click(sender As Object,iTotal As Int32) As Single
        If iItems = 0 Then
            Dim OurOwnExcption As New ArgumentException("iItems cannot be zero.") '自定义异常信息
            Throw OurOwnExcption
        End If

        Try
            Dim sngAverage As Single
            sngAverage = CSng(iTotal \ iItems)
            MessageBox.Show("sucessful")
            Return sngAverage
        Catch exD As DivideByZeroException
            MessageBox.Show("zero exception")
            Throw exD  '抛出异常,将结束整个捕获过程。此处会异常,因不再有捕获,程序会直接中断
            MessageBox.Show("More throw,but never executed")
        Catch exG As Exception
            MessageBox.Show("generic exception")
            Throw exG
        Finally
            MessageBox.Show("last step")
        End Try
    End Function

End Class

结果显示如下:







六、嵌套Try结构


由于异常可能在Try结构中Catch中,为了进一步捕获异常,可以Catch块中再次套用Try结构。



1、 InnerException和TargetSite


TargetSite属性,表示异常所发生处位置哪个方法,这个方法用字串形式表示 。

InnerException属性用于存储异常的跟踪信息。中文意:内部异常。是什么意思呢?

A->B

上面最初是A引发了异常,这个异常又触发了异常B。那么B的内部异常就是A。因为外表看到常是异常B,用这个属性来查看异常A。


这种一层一层产生的一系统异常,可以用Exception对象的InnerException属性,将异常放入栈中,代以后引用。

当一个异常进入堆栈时,前一个Exception对象就变成了堆栈的内部异常。

这是什么意思呢?

如图,当没有任何异常时,上面堆栈中异常为空,如果有了A就会进入堆栈,由于前面没有异常,所以A的内部异常即innerException就是空。

如果又发生了异常B,B就会再次进入堆栈,此时异常A就会变成异常B的内部异常InnerException。

同理,又发生了C,C异常进入栈中,此时B又成了C的内部异常。以此类推。

Public Class Form1

    Private Sub Button1_Click(sender As Object,e As EventArgs) Handles Button1.Click
        HandlerExample()

    End Sub
    Private Sub HandlerExample()
        Dim intX As Int32
        Dim intY As Int32
        Dim intZ As Int32
        intY = 0
        intX = 5

        Try
            intZ = CType(intX \ intY,Int32)
        Catch objA As System.DivideByZeroException
            Try
                Throw (New Exception("==0 as divisor==",objA))
            Catch objB As Exception
                Dim sError As String
                sError = "My Message:" & objB.Message & vbCrLf & vbCrLf
                sError &= "Inner Exception Message:" & objB.InnerException.Message & vbCrLf & vbCrLf
                sError &= "Method Error Occurred:" & objB.TargetSite.Name
                MessageBox.Show(sError)
            End Try
        Catch
            MessageBox.Show("Caught any other errors")
        Finally
            MessageBox.Show(Str(intZ))
        End Try
    End Sub

End Class

上面再次抛出异常时,把objA作为内部异常。结果如下:



上面例子不是很好,因为在Throw构造的异常中,是把objA本身就作为了内部异常进构建,再来显示内部 异常。

下面是微软的一个例子:

Imports System
Public Class MyAppException
    Inherits ApplicationException

    Public Sub New(message As [String])
        MyBase.New(message)
    End Sub
    Public Sub New(message As [String],inner As Exception)
        MyBase.New(message,inner)
    End Sub
End Class

Public Class ExceptExample
    Public Sub ThrowInner()
        Throw New MyAppException("First===")
    End Sub

    Public Sub CatchInner()
        Try
            Me.ThrowInner()
        Catch e As Exception
            Throw New MyAppException("Second===",e)
        End Try
    End Sub
End Class

Public Class Test
    Public Shared Sub Main()
        Dim testInstance As New ExceptExample()
        Try
            testInstance.CatchInner()
        Catch e As Exception
            Console.WriteLine("In Main catch block. Caught: {0}",e.Message)
            Console.WriteLine("---------------------")
            Console.WriteLine("Inner Exception is {0}",e.InnerException)
        End Try
        Console.Read()
    End Sub
End Class

这个例子较好地显示了内部异常。结果如下:










2、Source、StackTrace


发生异常时,首先要确定的是异常的名称和异常所处的位置,上面两个就是指出这两个属性的。

    Private Sub HandlerExample()
        Dim intX As Int32
        Dim intY As Int32
        Dim intZ As Int32
        intY = 0
        intX = 5

        Try
            intZ = CType(intX \ intY,Int32)
        Catch objA As System.DivideByZeroException
            objA.Source = "HandlerExample"
            MessageBox.Show(objA.Source & objA.StackTrace) '显示位置
        Finally
            MessageBox.Show(Str(intZ))
        End Try
    End Sub










3、GetBaseException

前面InnerExcetion已经演示了一系统异常入栈的情况:

A->B->C

从外层只能看到异常C,但有时我们得知道最终是哪个引起的。就会从外层C追起:

找C的InnerException,它是B

找B的InnerException,它是A

找A的InnerException,它是空,就是它

当一个异常的InnerException为空时,这个异常就是最终产生的异常的地方,即BaseException

    Private Sub HandlerExample()
        Dim intX As Int32
        Dim intY As Int32
        Dim intZ As Int32
        intY = 0
        intX = 5

        Try
            intZ = CType(intX \ intY,Int32)
        Catch objA As System.DivideByZeroException
            Try
                Throw New Exception("0 as divsior==",objA)
            Catch objB As Exception
                Try
                    Throw New Exception("new error",objB)
                Catch objC As Exception
                    MessageBox.Show(objC.GetBaseException.Message.ToString)
                End Try
            End Try
        Finally
            MessageBox.Show(Str(intZ))
        End Try
    End Sub

上面就是objA->objB->objC,所以BaseException就是ObjA,即除0的异常:











4、HelpLink

发生异常时,获得的帮助链接,常人为设置:

Private Sub HandlerExample()
        Try
            Dim a As New Exception("an error")
            a.HelpLink = "www.baidu.com"
            Throw a
        Catch ex As Exception
            Shell("explorer.exe " & ex.HelpLink)
        End Try
    End Sub













七、事件日志


异常发生后,我们常用日志写入文件中。 windows事件日志为三种:系统日志、应用程序日志、安全日志

事件日志有5种类型:信息事件、错误事件、警告事件、审核成功事件、审核失败事件。


事件日志中有很多记录,每条记录被称为条目。


条目(记录)必须有Source属性,它由程序员分配给事件的字符串,以利于在日志中对事件分类


一个条目要进入事件日志中,必须对这个事件源(产生这个条目的程序或系统服务等)进行注册,即把相应的字符串写进入。

如果没指定事件源(注意不是Source属性),直接写入事件条目的话,会发生错误

它相当于商家进入售前必须进行工商注册一样。


EventLog就是位置System.Diagnostics空间的类,它用于操作事件日志。


EventLog事件:

EntryWritten 当事件写入日志时发生


EventLog方法

CreatEventSource 为指定日志创建一个事件源

DeleteEventSource 删除一个事件源和与之相关联的记录项

WriteEntry 为指定的日志写入字符串

Exists 判断指定的事件日志是否存在

SourceExists 判断指定的源是否存在于日志中(下例中会用到)

GetEventLogs 检索指定计算机中所有事件日志的列表

Delete 删除整个事件日志


EventLog属性

source 指定要写入的记录项的源

Log 用于指定写入民,有系统、应用程序和安全日志3类日志,如果不指定,则默认情况下写入系统日志。

Public Class Form1

    Private Sub Button1_Click(sender As Object,e As EventArgs) Handles Button1.Click
        loggingExample()
    End Sub

    Sub loggingExample()
        Dim objLog As New EventLog()
        '指定事件日志项的事件类型,即信息事件、错误事件、审核失败事件、审核成功事件、警告事件共5类
        '事件类型只能是其中一种。因为事件查看器根据类型来确定显示的图标
        Dim objLogEntryType As EventLogEntryType

        Try
            Throw New EntryPointNotFoundException()
        Catch ex As Exception
            '用共享方法检查是否存在
            If Not EventLog.SourceExists("vb2012") Then '确定事件源是否已在本地计算机上注册
                EventLog.CreateEventSource("vb2012","System")
            End If

            objLog.Source = "Example"
            objLog.Log = "System"
            objLogEntryType = EventLogEntryType.Information
            objLog.WriteEntry("Error: " & ex.Message,objLogEntryType)
        End Try
    End Sub
    
End Class

对照一下结果:











八、写入文件


上面是写入到日志中,还可以写入到自定义文件中。

下面利用Debug类进行监听对象,用于收集、存储信息,并发送给文本文件

StreamWriter用于流文件写入到硬盘中。


    Sub loggingExample()
        Dim objWriter As New IO.StreamWriter("D:\mytext.txt",True)  '建立输出流
        Debug.Listeners.Add(New TextWriterTraceListener(objWriter))  '添加监听对象

        Try
            Throw New EntryPointNotFoundException() '强制抛出入口点异常(如:没找到该方法)
        Catch ex As Exception
            Debug.WriteLine(ex.Message) '写入监听缓冲
            objWriter.Flush()    '清理当前编写器缓冲,并将所有缓冲数据写入基础流。释放资源
            objWriter.Close()
            objWriter = Nothing
        End Try
    End Sub


猜你在找的VB相关文章