Проблема с переменной, установленной на переменную в VBS
В моей VBS, которую я использую вместе с SecureCRT для автоматизации некоторых процессов на устройствах Cisco, у меня есть (очень урезанный) следующий код:
Sub prConnectToHost(strConnectHost)
'If no host is passed into subroutine then we need to prompt for one.
If strConnectHost = "" Then strConnectHost = LCase(crt.Dialog.Prompt("Enter hostname or IP address:", "Connect to a host", strHost, False))
strHost = strConnectHost
'If user hits Cancel or hits Ok with no hostname entered then exit.
If strHost = "" Then
booReconnect = False
Exit Sub
End If
'Write to connection log
Call prWriteToConnectionLog
'Run command capture subroutine.
Call prCommandLoop
Set intWaitString = Nothing: Set strScreenGet = Nothing
Set strLatestScriptVersion = Nothing: Set strConnectHost = Nothing
End Sub
Sub Main имеет такой раздел:
Do While booReconnect = True
Call prConnectToHost("")
Loop
crt.Dialog.Prompt
такой же как MsgBox
, только он центрируется на окне, а не на экране, поэтому он немного аккуратнее. Переменная strHost
фактическая строка имени хоста, которая является глобальной в сценарии и содержит имя хоста, к которому мы хотим подключиться. Используется в Prompt
в качестве текста по умолчанию, идея заключается в том, что если вы отключите и booReconnect
флаг установлен, это Sub
вызывается снова, и в следующий раз, когда вам будет предложено ввести имя хоста, будет указано старое имя - полезно, если вы в первый раз написали его неправильно или вы подключаетесь к группе устройств с похожим именем.
Вы можете увидеть, где мы звоним prCommandLoop
в конце этого Sub
, который представляет собой цикл, который использует crt Function
называется WaitForStrings
который удерживает скрипт до тех пор, пока не найдет определенную последовательность строк. Когда это происходит, он запускает какие-то вещи, а затем возвращается назад, пока снова не ждет.
Одна из команд автоматизации обнаруживает наличие меню подключения (поэтому мы завершили сеанс маршрутизатора) и запрашивает у пользователя другое имя хоста для подключения.
Важный бит находится в очистке переменной в конце - Set strConnectHost = Nothing
, Если я оставлю это и сразу выйду prCommandLoop
с booReconnect
установить, как только Set strConnectHost = Nothing
применены, strHost
умирает - если я пытаюсь ссылаться на него, я получаю ошибку Object Variable not set
, Я экспериментировал с положением MsgBox strHost
линия прямо в конце Sub
, который доказал это.
Странно то, что если я выберу другую команду автоматизации в prCommandLoop
а затем выйти из сессии, Set strConnectHost = Nothing
никого не беспокоит.
Может кто-нибудь помочь мне объяснить, почему это проблема, так как это сбивает меня с толку. Я могу легко обойти это (не выдавая Set strConnectHost = Nothing
в конце prConnectToHost
Саб), но я просто хочу понять, в чем проблема.
1 ответ
Set используется для назначения объектов переменным. Ничто не думайте как особый объект
>> WScript.Echo IsObject(Nothing)
>>
-1
что полезно только для указания пустоты переменной. Ваш
Set strConnectHost = Nothing
назначает это Ничто для strConnectHost. После этого переменная бесполезна - она содержит пустой объект, который нельзя распечатать или использовать в вычислениях или попросить сделать методы.
Мошенничество с префиксом типа (*str* ConnectHost) должно предупредить вас, что это подозрительно. Вы работаете со строками (и числами?); чтобы очистить / сбросить их, используйте (простое) назначение с пустым:
>> strConnectHost = Empty
>>
>> WScript.Echo IsEmpty(strConnection)
>>
-1
или с подходящим значением:
intWaitString = -1 ' or 0 ...
(при условии, что intWaitString не является другим мошенничеством с префиксами типов).
ВТОРАЯ ПОПЫТКА:
Я предполагаю, что вы называете свою сабу так:
strHost = "SomeHost"
prConnectToHost strHost
Соответствующий дайджест вашего саба:
Sub prConnectToHost( [ByRef] strConnectHost)
...
Set strConnectHost = Nothing
End Sub
Поскольку VBScript по умолчанию использует передачу параметров по ссылке, ваша модификация изменяет переменную вызывающей стороны strHost. Это происходит и с необъектными переменными:
Dim sVar : sVar = "String 0"
WScript.Echo 0, sVar
changeString sVar
WScript.Echo 1, sVar
Sub changeString( sByRefVar )
sByRefVar = "String 1: changed by changeString( ByRef sByRefVar )"
End Sub
выход:
0 String 0
1 String 1: changed by changeString( ByRef sVar )
В вашем случае модификация присваивает Nothing переменной, которая называется strConnectHost в Sub и strHost на уровне вызывающей стороны. Как я уже говорил, это делает переменную бесполезной (кроме проверки на Is Nothing).
Я надеюсь, что это объясняет забивание strHost.
WRT 'управление памятью': за исключением очень особых случаев, вам не нужно очищать / сбрасывать / устанавливать переменные SetToNothing в VBScript. Использование локальной переменной в ваших Subs/Functions - это все, что необходимо. Если вы решили использовать глобальные переменные и сами управлять их состоянием, вы должны обратить внимание на типы переменных: изменение типа с объекта (включая Nothing) <=> необъектное и ложь о типах путем введения в заблуждение префиксов типов опасно / наверняка путь к опустошению. Если вы думаете, что должны очистить strHost, присвойте Empty или "" strConnectHost.
СЛЕДУЮЩАЯ ДОБАВКА
Все переменные VBScript являются вариантами, но не все варианты созданы равными:
>> s0 = "string"
>> s1 = CStr( 12.35 )
>> WScript.Echo TypeName( s0 ), TypeName( s1 )
>>
String String
>> n0 = 1
>> n1 = CByte( n0 )
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte
TypeName () и VarType() показывают подтипы, и программист может использовать наборC[hange/onvertTo]<Type>()
функции для их реализации - в некоторой степени, поскольку назначения могут изменять типы "под капотом".
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Integer Byte
>> n0 = 1.1
>> n1 = 2 ^ 20
>> WScript.Echo TypeName( n0 ), TypeName( n1 )
>>
Double Double
Есть даже ошибки несоответствия типов:
>> WScript.Echo Nothing
>>
Error Number: 13
Error Description: Type mismatch
>>
>> WScript.Echo s0 Is Nothing
>>
Error Number: 424
Error Description: Object required
Так что подтипы имеют значение. Некоторые люди думают, что префиксы типов не круты, но другие видят в них ценную помощь в слабо типизированных языках. Если вы решили использовать их, вы должны использовать их правильно -
Set strWhatEver = objWhatever
objWhatever = intWhatever
intWhatever = objWhatever
If strWhatEver = intWhatever Then
все пахнут (не обращая внимания на типы и трудно определить ошибки в последующем коде).