Ничего.
Err
часто рассматривается как некий глобальный ErrObject
экземпляр, но на самом деле это функция, которая возвращает единицу, как показано в обозревателе объектов:
![enter image description here](https://i.stack.imgur.com/Q3PIo.png)
И эта функция реализована таким образом, что вы всегда получаете один и тот же объект.
Объекты должны предоставлять доступный для использования интерфейс, поэтому объект, возвращаемый функцией Err
, предоставляет объект класса ErrObject
- это не означает, что класс ErrObject
существует, чтобы его можно было создать или инкапсулирован пользовательским кодом: он просто предоставляет интерфейс для доступа к свойствам текущего состояния ошибки времени выполнения.
Когда вы инкапсулируете ErrObject
, как вы это сделали, вы, по сути, просто предоставляете себе другой способ (помимо функции Err
) для доступа к экземпляру ErrObject
- но это все тот же объект, содержащий свойства текущее состояние ошибки времени выполнения .
И когда свойства объекта изменятся, ваша инкапсулированная копия, которая указывает на этот объект, начнет сообщать о новых значениях, а старые, которые вы хотели «запомнить», будут перезаписаны.
Обратите внимание, что это верно для любого объекта, а не только ErrObject
.
Скажем, у меня есть класс, который делает то, что вы делаете, со ссылкой 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
Если я сделаю экземпляр этого класса (назовем его 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, если состояние используется в момент, когда состояние глобальной ошибки уже содержит ту же информацию, нет необходимости делать это.
Класс можно довольно легко использовать [ab] в качестве возвращаемого типа для Function
, который возвращает Nothing
для обозначения успеха, и инкапсулированного состояния ошибки в случае сбоя - проблема в том, что язык разработан на основе поднимает ошибок, а не возвращает их; слишком легко «запустить и забыть» такую функцию, не проверяя ее возвращаемое значение, и, поскольку на сайте вызова фактическое состояние ошибки времени выполнения не собирается отключать оператор On Error
, несущий состояние ошибки: данные программы не идиоматичны, они создают «удивительный» API, который может легко привести к тому, что код будет игнорировать все ошибки.
Идиоматическая обработка ошибок обрабатывает глобальное состояние ошибки времени выполнения как можно скорее и либо восстанавливает в той же области, либо позволяет состоянию ошибки пузыриться в стеке вызовов там, где его можно обработать. И пока ошибка не будет обработана, состояние ErrObject
доступно через глобальную функцию Err
.