[英]VBA dictionary <out of context> after Sub is run
我正在尝试运行以下代码来创建字典,然后将其用于函数中,以根据字典键分配函数参数值。
Option Explicit
Public b1 As Object
Public var1 As Variant
Public var2 As String
Public var3 As Variant
Sub CreateDictionaries()
Set b1 = CreateObject("Scripting.Dictionary")
b1.Add "key1", 0.009
b1.Add "key2", 0.011
b1.Add "key3", 0.014
b1.Add "key4", 0.025
b1.Add "key5", 0.045
End Sub
Public Function MyFunction(var1, var2, var3)
If var1 <= 5 Then
MyFunction = b1.Item(var2) * var1* var3
ElseIf var1 > 5 And var1 <= 10 Then
MyFunction = b1.Item(var2) * (var1 - 5) * var3
ElseIf var1 > 10 Then
MyFunction = b1.Item(var2) * (var1 - 10) * var3
End If
End Function
尽管此方法起初很有效,但在我将Sub临时更改为Static Sub之后,它停止了工作。 将其改回其最后的工作状态仍无法解决问题。 重新启动VBA并将代码作为新模块运行也没有用。
调试时,我可以在“监视”窗口中看到按需创建的字典b1,但是在Sub完成后,它将取值为“上下文无关”。 这没有任何意义,现在让我发疯! 有人可以帮忙吗?
要点:
添加对Microsoft脚本运行时库的引用; 这将允许您使用实际类型,而不是普通对象:
Public b1 As Scripting.Dictionary
您可以使用New
语法初始化字典:
Public b1 As New Scripting.Dictionary
尽管这只会创建字典; 它不会填满它; 这给我们带来了下一点。
AFAIK,在VBA中没有模块的构造方法。 因此,在尝试使用字典之前,您必须验证字典是否已填充,并可能还要测试初始化:
Public b1 As Scripting.Dictionary Sub InitializeDictionary() If Not b1 Is Nothing Then Exit Sub Set b1 = New Scripting.Dictionary b1.Add "key1", 0.009 b1.Add "key2", 0.011 b1.Add "key3", 0.014 b1.Add "key4", 0.025 b1.Add "key5", 0.045 End Sub Public Function MyFunction(var1, var2, var3) InitializeDictionary If var1 <= 5 Then MyFunction = b1.Item(var2) * var1* var3 ElseIf var1 > 5 And var1 <= 10 Then MyFunction = b1.Item(var2) * (var1 - 5) * var3 ElseIf var1 > 10 Then MyFunction = b1.Item(var2) * (var1 - 10) * var3 End If End Function
Static
关键字在这里不会有所作为。 根据文档 ,在Function
或Sub
上使用Static
关键字:
指示在调用之间保留
Sub
过程的局部变量。 即使在过程中使用了Static
属性,Static
属性也不会影响在Sub
外部声明的变量。
在这种情况下, b1
变量已在Sub
外部声明。
使用Static
语句声明模块级变量(例如b1
)也不会起作用-在这两种情况下,值都将持续到重置代码为止。 它仅在过程中声明变量时有所不同。
关于“监视”窗口和变量<out of context>
,在VBA IDE中添加Watch时,需要将上下文指定为<all procedures>
和<all modules>
。 否则,仅当调试器在所选模块内和所选过程内停止时,才会评估Watch变量。
在函数内部创建一个Static
Dictionary
。 首次使用该函数时,将填充该词典,但此后将保留值,并跳过相关代码。
Option Explicit
Public Function MyFunction(var1, var2, var3)
Static b1 As Object
If b1 Is Nothing Then
Set b1 = CreateObject("Scripting.Dictionary")
b1.Add "key1", 0.009
b1.Add "key2", 0.011
b1.Add "key3", 0.014
b1.Add "key4", 0.025
b1.Add "key5", 0.045
End If
If var1 <= 5 Then
MyFunction = b1.Item(var2) * var1* var3
ElseIf var1 > 5 And var1 <= 10 Then
MyFunction = b1.Item(var2) * (var1 - 5) * var3
ElseIf var1 > 10 Then
MyFunction = b1.Item(var2) * (var1 - 10) * var3
End If
End Function
正如其他人指出的那样,通常最好尽早绑定变量。 这意味着如果你知道你想要一个Dictionary
对象,避免声明一个Object
,然后再将其转换为一个Dictionary
时,你可以声明为一个Dictionary
的时候了。 为此,您需要包括对脚本运行时库的引用,并使用:
Dim b1 As Scripting.Dictionary
Set b1 = New Scripting.Dictionary
不要使用下面的单个As New
语句,因为它可能导致不必要的错误(更多信息请参见此处)
Dim b1 As New Scripting.Dictionary
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.