如果永远只能存在一个错误对象,那么声明一个 ErrObject 变量有什么用呢?
What is the use of declaring an ErrObject variable if there can only ever exist one error object?
我们都知道 VBA.
中永远只能有一个错误对象
在帮助同事处理错误以及为什么他不应该使用 On Error Resume Next
时,我有一个想法:
将错误对象存储在某处以供以后引用。
考虑这段测试代码:
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 到立即数 window 因为 On Error GoTo 0
重置错误对象然后打印 1 因为它仍然持有对唯一错误对象 (?) 的引用。
如果我们创建一个新的 class 并为其提供一些与 ErrObject 相关的属性,如下所示:
(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 作为输出。
这让我想到了我的问题:当我们无法创建一个新对象本身但它只是成为指向 [=34 中唯一错误对象的另一个指针时,将变量声明为 ErrObject 有什么用=]?
None随便。
Err
通常被视为某种全局 ErrObject
实例,但事实是,它是 returns 的函数一个 - 如对象浏览器中所示:
并且该功能的实现方式始终是相同的对象。
对象需要公开一个可用的接口,因此由 Err
函数编辑的对象 return 公开了 ErrObject
class 的对象 - 它不会这并不意味着 ErrObject
class 存在,因此它可以被用户代码实例化或封装:它只是提供一个接口来访问当前 运行-time 错误状态的属性。
当你像你那样封装一个 ErrObject
时,你基本上只是给自己另一种方式(除了 Err
函数)来访问 ErrObject
实例 - 但它仍然是保存 当前 运行 时间错误状态 .
属性的完全相同的对象
当一个对象的属性发生变化时,指向该对象的封装副本将开始报告新值,而您打算 "remember" 的旧值将被覆盖。
请注意,这适用于任何对象,而不仅仅是 ErrObject
。
假设我有一个 class 可以执行您对 ErrObject
引用所做的操作,但具有 Collection
:
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
如果我创建一个 class 的实例(我们称它为 Class1
)并将 c
分配给它的 InternalCollection
,然后将项目添加到 c
...
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
输出是 2
,因为 c
和 InternalCollection
(/封装的 coll
引用)是完全相同的对象,这就是封装的情况ErrObject
.
解决方案是 不 封装 ErrObject
本身,而是将其值拉入封装 的仅获取属性的支持字段ErrObject
的状态:
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
'...
现在,这是否有用还有待商榷 - IMO 如果在全局错误状态已包含相同信息的时刻消耗状态,则无需执行此操作。
class 很容易被 [ab] 用作 Function
的 return 类型,returns Nothing
表示成功,以及失败时封装的错误状态——问题是语言是围绕 raising 错误而不是 returning 错误设计的;在不验证其 return 值的情况下 "fire-and-forget" 这样的函数太容易了,并且由于在调用站点 actual 运行time 错误状态是'不会触发 On Error
语句,携带错误状态作为 程序数据 不是惯用的,它使 "surprising" API 很容易导致在最终忽略所有错误的代码中。
惯用错误处理会尽快处理全局 运行time 错误状态,并在同一范围内恢复,或者让错误状态在调用堆栈中冒泡到可以处理的位置。在处理错误之前,可以通过全局 Err
函数访问 ErrObject
状态。
我们都知道 VBA.
中永远只能有一个错误对象
在帮助同事处理错误以及为什么他不应该使用 On Error Resume Next
时,我有一个想法:
将错误对象存储在某处以供以后引用。
考虑这段测试代码:
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 到立即数 window 因为 On Error GoTo 0
重置错误对象然后打印 1 因为它仍然持有对唯一错误对象 (?) 的引用。
如果我们创建一个新的 class 并为其提供一些与 ErrObject 相关的属性,如下所示:
(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 作为输出。
这让我想到了我的问题:当我们无法创建一个新对象本身但它只是成为指向 [=34 中唯一错误对象的另一个指针时,将变量声明为 ErrObject 有什么用=]?
None随便。
Err
通常被视为某种全局 ErrObject
实例,但事实是,它是 returns 的函数一个 - 如对象浏览器中所示:
并且该功能的实现方式始终是相同的对象。
对象需要公开一个可用的接口,因此由 Err
函数编辑的对象 return 公开了 ErrObject
class 的对象 - 它不会这并不意味着 ErrObject
class 存在,因此它可以被用户代码实例化或封装:它只是提供一个接口来访问当前 运行-time 错误状态的属性。
当你像你那样封装一个 ErrObject
时,你基本上只是给自己另一种方式(除了 Err
函数)来访问 ErrObject
实例 - 但它仍然是保存 当前 运行 时间错误状态 .
当一个对象的属性发生变化时,指向该对象的封装副本将开始报告新值,而您打算 "remember" 的旧值将被覆盖。
请注意,这适用于任何对象,而不仅仅是 ErrObject
。
假设我有一个 class 可以执行您对 ErrObject
引用所做的操作,但具有 Collection
:
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
如果我创建一个 class 的实例(我们称它为 Class1
)并将 c
分配给它的 InternalCollection
,然后将项目添加到 c
...
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
输出是 2
,因为 c
和 InternalCollection
(/封装的 coll
引用)是完全相同的对象,这就是封装的情况ErrObject
.
解决方案是 不 封装 ErrObject
本身,而是将其值拉入封装 的仅获取属性的支持字段ErrObject
的状态:
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
'...
现在,这是否有用还有待商榷 - IMO 如果在全局错误状态已包含相同信息的时刻消耗状态,则无需执行此操作。
class 很容易被 [ab] 用作 Function
的 return 类型,returns Nothing
表示成功,以及失败时封装的错误状态——问题是语言是围绕 raising 错误而不是 returning 错误设计的;在不验证其 return 值的情况下 "fire-and-forget" 这样的函数太容易了,并且由于在调用站点 actual 运行time 错误状态是'不会触发 On Error
语句,携带错误状态作为 程序数据 不是惯用的,它使 "surprising" API 很容易导致在最终忽略所有错误的代码中。
惯用错误处理会尽快处理全局 运行time 错误状态,并在同一范围内恢复,或者让错误状态在调用堆栈中冒泡到可以处理的位置。在处理错误之前,可以通过全局 Err
函数访问 ErrObject
状态。