Я недавно натолкнулся на `Значения атрибутов. VB_UserMemId = 0 '.Мне нравятся списки, поэтому я подумал, что должен создать объект типа коллекции на заказ.
Минимальный код для класса, который может воспроизвести ошибку:
Класс Lst
Option Explicit
Public c As New Collection
'this is the default property
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
If IsMissing(index) Then
Set item = Me
'DoEvents
Else
item = c(index)
End If
End Property
Public Property Let item(Optional index, itm)
If IsMissing(index) Then 'assume itm is list
If IsObject(itm) Then Set c = itm.c Else c.add itm
Else
c.add itm, , index
c.Remove index + 1
End If
End Property
По существу, lst(i)
возвращаетi-й элемент частной коллекции Lst(i)=6
устанавливает i-й элемент.(Обработка ошибок и проверка индекса кода удалены для ясности).
Я заметил, что объекты, которые возвращают себя из свойства по умолчанию, могут быть возвращены из функции в варианте (например, LstFunc=L
ниже), без необходимости set
удаления сложности из глаз моих студентов ... (Вы не можете сделать это с объектом коллекции)
К сожалению, я столкнулся с двумя проблемами ... минимальный код для них:
Проблема
Function LstFunc() As Variant
Dim L As New Lst
L = 4 'replaces L.item=3
LstFunc = L 'this is not normally allowed, but desirable (for me!)
End Function
Sub try()
Dim L As New Lst
L = LstFunc 'replaces L.item=LstFunc-->L.c: [4]
L = 3 'L.c: [4,3]
If L = 6 Then DoEvents
End Sub
Вот что происходит
1), когда выражение L = 6
оценивается как Excel зависает.Иногда ESC
возвращает вас обратно, но мой опыт показывает, что Excel перестает отвечать и нуждается в перезагрузке.
Чтобы оценить выражение, сначала вызывается функция L.item, возвращая Lst
, для которого вызывается элемент и т. Д.приводя к нежелательному и необнаруженному бесконечному повторению (не совсем рекурсия).Раскомментируя оператор DoEvents
в свойстве get item, вы можете без сбоев остановиться
2) после раскомментирования DoEvents
я шаг за шагом запускаю режим отладчика.Если я теперь наведу курсор мыши (случайно ...) на переменную L, отладчик зависнет, и я получу зеленый треугольник смерти , который, боюсь, очень запутает студентов:
Обратите внимание, что это поведение можно восстановить, если оператор DoEvents
в классе снова закомментирован.Настоящий улов 22 ...
Немного сложного в этом, но любые предположения относительно того, как я могу поймать нежелательное повторение в (1) при низких вычислительных затратах и без потери способности передавать объект каквариант был бы принят.
PS это код, который предоставляет небезопасный обходной путь, обсуждаемый в комментарии ниже:
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
static i
If IsMissing(index) Then
Set item = Me
i=i+1:if i>1000 then item="":exit property
'DoEvents
Else
item = c(index)
i=0
End If
End Property