0

在我使用的 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你可以在 this 的末尾看到我们调用的位置Sub,这是一个循环,它使用crt Function调用WaitForStrings的方法将脚本置于暂停状态,直到找到特定的字符串序列。当它发生时,它会触发一些东西,然后循环回来,直到它再次等待。

其中一个自动化命令检测连接菜单的存在(因此我们退出了路由器会话)并提示用户输入另一个主机名来连接。

重要的一点是在最后的变量 clearup - Set strConnectHost = Nothing。如果我把它留在里面并立即退出set prCommandLoopbooReconnect一旦Set strConnectHost = Nothing应用,strHost就会死掉 - 如果我尝试引用它,我会得到一个错误Object Variable not set。我尝试在 结尾处放一条MsgBox strHost线Sub,这证明了这一点。

奇怪的是,如果我prCommandLoop先选择不同的自动化命令然后退出会话,这Set strConnectHost = Nothing似乎不会打扰任何人。

谁能帮我解释为什么这是一个问题,因为它让我感到困惑。我可以轻松地解决它(通过不在SubSet strConnectHost = Nothing末尾发布prConnectToHost),但我只想了解问题所在。

4

1 回答 1

0

Set用于将对象分配给变量。将Nothing视为一个非常特殊的对象

>> WScript.Echo IsObject(Nothing)
>>
-1

这仅用于指示变量的空性。您的

Set strConnectHost = Nothing

将此 Nothing 分配给 strConnectHost。在那之后,这个变量就没有用了——它保存了不能打印或在计算中使用或被要求执行方法的空对象。

类型前缀欺诈 (* str *ConnectHost) 应该提醒您这是可疑的。您使用字符串(和数字?);要清除/重置它们,请使用 Empty 的(简单)分配:

>> 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 分配给 Sub 中称为 strConnectHost 的变量和调用者级别的 strHost 。正如我之前所说,这使得变量无用(除了对 Is Nothing 的测试)。

我希望这可以解释 strHost 的崩溃。

WRT '内存管理':除了非常特殊的情况,您不需要在 VBScript 中清除/重置/SetToNothing 变量。在您的 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

所有气味(不注意类型并且难以在以后的代码中确定错误)。

于 2011-08-23T12:21:41.037 回答