VBA UserForm выдает ошибку времени выполнения 91 для одного из своих параметров - PullRequest
1 голос
/ 06 ноября 2019

Я пытаюсь создать несколько экземпляров одной немодальной пользовательской формы в Excel-VBA с параметрами через Sub.

Я могу заставить его работать с двумя из трех параметров, которые я хочу назначить, но третий постоянно возвращает мне

"Ошибка времени выполнения" 91 ": переменная объекта илиС переменной блока не установлено "

, и я не могу понять, почему. Это может быть очевидная опечатка, которую я не видел, но я действительно не могу указать на проблему. Вот мой код:

Sub AskToClose(targetWksht As Worksheet, targetRow As Integer, test As String)
    Dim newInstanceOfMe As Object

    Set newInstanceOfMe = UserForms.Add("MOVE_TO_CLOSED") 'MOVE_TO_CLOSED is the name of my UserForm

    newInstanceOfMe.targetWksht = targetWksht 'If I comment this line it works just fine, otherwise Run-time error 91
    newInstanceOfMe.targetRow = targetRow
    newInstanceOfMe.test = test

    newInstanceOfMe.Show vbModeless
End Sub

_____________________________________________________________________

Sub test()
    Dim openWksht As Worksheet

    Set openWksht = Worksheets("OPEN WO") 'The worksheet exists and works just fine everywhere else

    Call AskToClose(openWksht, 2, "test 2")
    Call AskToClose(openWksht, 3, "test 3")
    Call AskToClose(openWksht, 4, "test 4")

    Set openWksht = Nothing 'I tried to comment this line just in case, same result...
End Sub

_____________________________________________________________________
'My MOVE_TO_CLOSED UserForm parameters
Public targetWksht As Worksheet
Public targetRow As Integer
Public test As String

1 Ответ

4 голосов
/ 06 ноября 2019
newInstanceOfMe.targetWksht = targetWksht

Этот оператор создает уровень ошибки качество кода результат проверки для Требуемое значение проверка в Rubberduck (открытыйисточник надстройки VBIDE, которым я управляю). Инспекция объясняет ситуацию следующим образом:

Объект используется там, где требуется значение

Компилятор VBA не выдает ошибку, если объект используется вместо, которое требует тип значения и объявленный тип объекта, не имеет подходящего члена по умолчанию. Почти при любых обстоятельствах это приводит к ошибке времени выполнения 91 «Объект или С переменной блока не установлено» или 438 «Объект не поддерживает это свойство или метод» в зависимости от того, имеет ли объект значение «Ничего» или нет,который сложнее обнаружить и указывает на ошибку.

В VBA существует два типа присвоений: присвоение значения (Let) и справочное присвоение (Set). Ключевое слово Let является избыточным / необязательным / устаревшим для присвоений значений:

Dim foo As Long
foo = 2 + 2
Let foo = 2 + 2 '<~ exactly equivalent to the above

Поэтому, если ключевое слово Set не присутствует, VBA пытается выполнить присвоение значений. Если у объекта есть член по умолчанию , это может сработать - спецификации VBA определяют, как механизмы let-coercion делают это. Вот как вы можете присвоить Range значению:

Sheet1.Range("A1") = 42

Это неявно присвоение Range.Value через неявный вызов члена для Range.[_Default], скрытое свойствокласс Range.

Если бы правая часть присваивания была также объектом, то с обеих сторон оператора происходило бы принудительное приведение:

Sheet1.Range("A1") = Sheet1.Range("B1") '<~ implicit default member calls galore!
Sheet1.Range("A1").Value = Sheet1.Range("B1").Value

Номы не смотрим Range здесь, мы смотрим на UserForm, а UserForm не имеет члена по умолчанию, поэтому принудительное приведение не может произойти ... но компилятор победил 'Это можно проверить, поэтому код все равно запускается ... и взорвется во время выполнения.

Итак, мы смотрим на присваивание Let с обеими сторонами, содержащими ссылку на объект, длятип класса, который не определяет член по умолчанию.

Something.SomeObject = someOtherObject

Но VBA не волнует, что нет члена по умолчанию - потому что нет ключевого слова Set, он старается изо всех силто, что вы сказали ему сделать, и привести эти объекты к значениям ... и не получится, очевидно.

ЕслиSomething.SomeObject (левая сторона) равно Nothing, тогда попытка let-coercion попытается вызвать несуществующий элемент по умолчанию - но поскольку ссылка на объект Nothing, вызов недопустим, и возникает ошибка 91.

Если Something.SomeObject уже содержит действительную ссылку на объект, то попытка let-coercion продвинется на один шаг дальше и завершится неудачно с ошибкой 438, потому что нет элемента по умолчанию для вызова.

Если Something.SomeObject имеет элемент по умолчанию (а ссылка не Nothing), тогда присвоение значения выполнено успешно, ошибка не возникает ... но ссылка на объект не была назначена, и это может бытьнебольшая ошибка!

Добавление ключевого слова Set делает назначение справочным назначением , и теперь все работает нормально.

...