繁体   English   中英

VBA字典 <out of context> 在Sub运行之后

[英]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关键字在这里不会有所作为。 根据文档 ,在FunctionSub上使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM