Проблема с переменной, установленной на переменную в 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

все пахнут (не обращая внимания на типы и трудно определить ошибки в последующем коде).

Другие вопросы по тегам