Vba 如果只能存在一个错误对象,那么声明一个ErrObject变量有什么用?
我们都知道VBA中只能有一个错误对象。 在帮助同事处理错误以及为什么他不应该在错误简历上使用“下一步”时,我有一个想法: 将错误对象存储在某个位置,以便以后引用回它 考虑这段测试代码:Vba 如果只能存在一个错误对象,那么声明一个ErrObject变量有什么用?,vba,error-handling,ms-office,Vba,Error Handling,Ms Office,我们都知道VBA中只能有一个错误对象。 在帮助同事处理错误以及为什么他不应该在错误简历上使用“下一步”时,我有一个想法: 将错误对象存储在某个位置,以便以后引用回它 考虑这段测试代码: Sub Test() Dim t As ErrObject On Error Resume Next Err.Raise 1 Set t = Err On Error GoTo 0 Debug.Print t.Number On Error Resume N
Sub Test()
Dim t As ErrObject
On Error Resume Next
Err.Raise 1
Set t = Err
On Error GoTo 0
Debug.Print t.Number
On Error Resume Next
Err.Raise 1
Debug.Print t.Number
End Sub
它会将0打印到即时窗口,因为在出现错误时,0会重置错误对象,然后打印1,因为它仍然保留对唯一错误对象的引用
如果我们创建一个新类,并给它一些与ErrorObject相关的属性,如下所示:
(TestClass)
Option Explicit
Public oError As ErrObject
Private Sub Class_Initialize(): End Sub
Private Sub Class_Terminate()
If Not oError Is Nothing Then Set oError = Nothing
End Sub
Public Property Get Error()
Error = oError
End Property
Public Property Set Error(ByVal ErrorObject As ErrObject)
Set oError = ErrorObject
End Property
然后像这样创建我们的实例:
Sub Test2()
Dim t As TestClass
On Error Resume Next
Set t = New TestClass
Err.Raise 1
Set t.Error = Err
On Error GoTo 0
Debug.Print t.oError.Number
On Error Resume Next
Err.Raise 1
Debug.Print t.oError.Number
End Sub
我们仍然分别得到0和1作为输出
这就引出了我的问题:当我们无法创建一个新对象本身,但它只是成为指向VBA中唯一错误对象的另一个指针时,将变量声明为ErrObject有什么用
Err通常被视为某种全局ErrObject实例,但事实是,它是一个返回一个实例的函数-如对象浏览器中所示:
这个函数是以这样的方式实现的,你总是得到相同的对象
对象需要公开一个可用的接口,因此Err函数返回的对象公开了ErrObject类的接口-这并不意味着ErrObject类的存在可以通过用户代码实例化或封装:它只提供一个接口来访问当前运行时错误状态的属性
当你像以前那样封装一个ErroObject时,你本质上只是给自己提供了除Err函数之外的另一种方式来访问ErroObject实例——但它仍然是保持当前运行时错误状态属性的完全相同的对象
当一个对象的属性发生变化时,指向该对象的封装副本将开始报告新值,而您想要记住的旧值将被覆盖
请注意,这适用于任何对象,而不仅仅是ErroObject
假设我有一个类,它完成了您对ErrObject引用所做的操作,但它有一个集合:
如果我创建了该类的一个实例,让我们将其命名为Class1,并将c分配给其InternalCollection,然后将项添加到c
输出为2,因为c和InternalCollection/encapsuated coll引用是同一个对象,这就是封装的ErroObject发生的情况
解决方案是不封装ErrObject本身,而是将其值拉入封装ErrObject状态的get-only属性的支持字段:
现在,这是否有用还有待讨论——在我看来,如果在全局错误状态已经包含相同信息的时刻使用状态,那么就没有必要这样做
该类可以很容易地被[ab]用作一个函数的返回类型,该函数不返回任何表示成功的内容,以及失败时封装的错误状态——问题是该语言是围绕引发错误而设计的,而不是返回错误;在不验证其返回值的情况下,很容易触发和忘记这样的函数,而且由于在调用站点,实际运行时错误状态不会触发On error语句,因为程序数据不是惯用的,所以会携带错误状态,这会生成一个令人惊讶的API,很容易导致代码忽略所有错误
惯用错误处理会尽快处理全局运行时错误状态,或者在同一范围内恢复,或者让错误状态在调用堆栈中冒泡到可以处理的位置。在错误得到处理之前,可以通过全局Err函数访问ErrObject状态。无
Err通常被视为某种全局ErrObject实例,但事实是,它是一个返回一个实例的函数-如对象浏览器中所示:
这个函数是以这样的方式实现的,你总是得到相同的对象
对象需要公开一个可用的接口,因此Err函数返回的对象公开了ErrObject类的接口-这并不意味着ErrObject类的存在可以通过用户代码实例化或封装:它只提供一个接口来访问当前运行时错误状态的属性
当你像以前那样封装一个ErroObject时,你本质上只是给自己提供了除Err函数之外的另一种方式来访问ErroObject实例——但它仍然是保持当前运行时错误状态属性的完全相同的对象
当一个对象的属性发生变化时,指向该对象的封装副本将开始报告新值,而您想要记住的旧值将被覆盖
请注意,这适用于任何对象,而不仅仅是ErroObject
假设我有一个类,它完成了您对ErrObject ref所做的操作
erence,但有一个集合:
如果我创建了该类的一个实例,让我们将其命名为Class1,并将c分配给其InternalCollection,然后将项添加到c
输出为2,因为c和InternalCollection/encapsuated coll引用是同一个对象,这就是封装的ErroObject发生的情况
解决方案是不封装ErrObject本身,而是将其值拉入封装ErrObject状态的get-only属性的支持字段:
现在,这是否有用还有待讨论——在我看来,如果在全局错误状态已经包含相同信息的时刻使用状态,那么就没有必要这样做
该类可以很容易地被[ab]用作一个函数的返回类型,该函数不返回任何表示成功的内容,以及失败时封装的错误状态——问题是该语言是围绕引发错误而设计的,而不是返回错误;在不验证其返回值的情况下,很容易触发和忘记这样的函数,而且由于在调用站点,实际运行时错误状态不会触发On error语句,因为程序数据不是惯用的,所以会携带错误状态,这会生成一个令人惊讶的API,很容易导致代码忽略所有错误
惯用错误处理会尽快处理全局运行时错误状态,或者在同一范围内恢复,或者让错误状态在调用堆栈中冒泡到可以处理的位置。在错误得到处理之前,可以通过全局Err函数访问ErrObject状态
Private coll As Collection
Public Property Set InternalCollection(ByVal c As Collection)
Set coll = c
End Property
Public Property Get InternalCollection() As Collection
Set InternalCollection = coll
End Property
Dim c As Collection
Set c = New Collection
With New Class1
Set .InternalCollection = c
c.Add 42
.InternalCollection.Add 42
Debug.Print .InternalCollection.Count
End With
Private errNumber As Long
Private errDescription As String
'...
Public Sub SetErrorInfo() 'note: an ErrObject argument would be redundant!
With Err
errNumber = .Number
errDescription = .Description
'...
End With
End Sub
Public Property Get Number() As Long
Number = errNumber
End Property
Public Property Get Description() As String
Description = errDescription
End Property
'...