编程技术网

关注微信公众号,定时推送前沿、专业、深度的编程技术资料。

 找回密码
 立即注册

QQ登录

只需一步,快速开始

极客时间

如果只能存在一个错误对象,则声明ErrObject变量有什么用?:What is the use of declaring an ErrObject variable if there can only ever exist one error object?

Richard Woodru 面向对象 2022-5-11 10:28 7人围观

腾讯云服务器
如果只能存在一个错误对象,则声明ErrObject变量有什么用?的处理方法

我们都知道VBA中只能有一个错误对象.在帮助同事进行错误处理以及为什么他不应该使用 On Error Resume Next 时,我有一个主意:将错误对象存储在某处,以供以后引用.

We all know there can only ever be one error object in VBA. While helping a co-worker with error handling and why he shouldn't use On Error Resume Next I had an idea: Store the error object somewhere to later reference back to it.

考虑这段测试代码:

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,因为 On Error GoTo 0 会重置错误对象,然后打印1,因为它仍然保留对唯一错误对象(?)的引用.

It will print 0 to the immediate window because On Error GoTo 0 resets the error object and then prints 1 since it still holds a reference to the only error object (?).

如果我们创建一个新类,并为它提供一些与ErrObject有关的属性,如下所示:

If we create a new class and give it some properties pertaining to the ErrObject like so:

(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 

并像这样创建我们的实例:

And create our instance like this:

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作为输出.

We still get 0 and 1 as output respectively.

这使我想到了一个问题:当我们无法创建新对象本身而只是将其变为VBA中唯一错误对象的另一个指针时,将变量声明为ErrObject有什么用?

This bringst me to my question: What is the use of declaring a variable as ErrObject when we cannot create a new object itself but it simply becomes another pointer to the only error object in VBA?

问题解答

什么都没有.

Err 通常被视为某种全局 ErrObject 实例,但事实是,它是返回的一个函数-如所揭示在对象浏览器中:

Err is often treated as some kind of global ErrObject instance, but the truth is, it's a function that returns one - as revealed in the object browser:

该函数的实现方式是,您总是得到相同的对象.

And that function is implemented in such a way, that you always get the same object.

对象需要公开一个接口才能使用,因此 Err 函数返回的对象公开了 ErrObject 类的对象-这并不意味着 <存在code> ErrObject 类,以便可以由用户代码实例化或封装该类:它仅提供用于访问当前运行时错误状态的属性的接口.

Objects need to expose an interface to be usable, and so the object returned by the Err function exposes that of the ErrObject class - it doesn't mean the ErrObject class exists so that it can be instantiated or encapsulated by user code: it merely provides an interface to access the properties of the current run-time error state.

当像您一样封装 ErrObject 时,您实际上只是在给自己另一种方式(除了 Err 函数之外)以访问 ErrObject 实例-但它仍然是完全相同的对象,具有当前运行时错误状态的属性.

When you encapsulate an ErrObject like you did, you're essentially just giving yourself another way (besides the Err function) to access the ErrObject instance - but it's still the exact same object holding the properties of the current run-time error state.

当对象的属性更改时,指向该对象的封装副本将开始报告新值,而您本想记住"的旧值将被覆盖.

And when an object's properties change, your encapsulated copy that points to that object is going to start reporting the new values, and the old ones you meant to "remember" are overwritten.

请注意,这适用于任何对象,而不仅仅是 ErrObject .

Note that this is true for any object, not just ErrObject.

说我有一个类,该类使用 ErrObject 引用执行您的操作,但是使用 Collection :

Say I have a class that does what you're doing with the ErrObject reference, but with a 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 

如果我创建该类的实例(我们称其为 Class1 ),并将 c 分配给其 InternalCollection ,然后将项目添加到 c ...

If I make an instance of that class (let's call it Class1) and assign c to its InternalCollection, and then add items to 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 就是这种情况.

The output is 2, because c and InternalCollection (/the encapsuated coll reference) are the very same object, and that's what's happening with your encapsulated ErrObject.

解决方案是封装 ErrObject 本身,而是将其值放入支持字段的后备字段中,该属性只封装了 state ErrObject :

The solution is to not encapsulate the ErrObject itself, but rather pull its values into backing fields for get-only properties that encapsulate the state of the 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,如果在全局错误状态已经包含相同信息的时刻消耗该状态,则无需这样做.

Now, whether that's useful is up for debate - IMO if the state is consumed at a moment where the global error state already contains the same information, there's no need to do this.

可以很容易地将该类用作[code] Function 的返回类型,该函数返回 Nothing 表示成功,并在失败时封装错误状态-问题是该语言是围绕引发错误而不是返回错误而设计的;在不验证其返回值的情况下触发并忘记"这样的函数太容易了,并且由于在调用站点, actual 实际运行时错误状态不会触发 On Error语句,它以错误状态表示为程序数据不是惯用的,它使API变得令人惊讶",可以很容易地导致最终导致忽略所有错误的代码.

The class could pretty easily be [ab]used as a return type for a Function that returns Nothing to indicate success, and the encapsulated error state in case of failure - the problem is that the language is designed around raising errors rather than returning them; it's too easy to "fire-and-forget" such a function without verifying its return value, and since at the call site the actual runtime error state isn't going to trip an On Error statement, carrying error state as program data isn't idiomatic, it makes a "surprising" API that can easily result in code that ends up ignoring all errors.

惯用错误处理将尽快处理全局运行时错误状态,并在相同的范围内进行恢复,或者使错误状态冒泡地将调用堆栈扩展到可以对其进行处理的位置.并且,在处理错误之前,可以通过全局 Err 函数访问 ErrObject 状态.

Idiomatic error handling deals with the global runtime error state as soon as possible, and either recovers in the same scope, or lets the error state bubble up the call stack to where it can be handled. And until the error is handled, the ErrObject state is accessible through the global Err function.

这篇关于如果只能存在一个错误对象,则声明ErrObject变量有什么用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程技术网(www.editcode.net)!

腾讯云服务器 阿里云服务器
关注微信
^