在运行Sub之后,VBA字典<out of =“”context =“”>

时间:2017-06-12 09:55:55

标签: excel-vba dictionary vba excel

我正在尝试运行以下代码来创建一个字典,然后在函数中使用该字典根据字典键分配函数参数值。

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更改为静态Sub后,它停止了工作。将其更改回最后的工作状态并没有解决问题。重新启动VBA并将代码作为新模块运行也无法正常工作。

调试时我可以在Watch窗口中看到字典b1是按原样创建的,但是在Sub完成之后,它会取值“out of context”。它没有任何意义,它现在让我发疯!有人可以帮忙吗?

2 个答案:

答案 0 :(得分:0)

有几点:

  • 添加对 Microsoft Scripting Runtime 库的引用;这将允许您使用实际类型,而不是普通对象:

    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关键字在这里不会产生任何影响。根据{{​​3}},StaticFunction上的Sub关键字:

      

    表示在调用之间保留Sub过程的局部变量。 Static属性不会影响在Sub之外声明的变量,即使它们已在过程中使用。

    在这种情况下,b1变量已在Sub之外声明。

    使用Static语句声明模块级变量(例如b1)也不起作用 - 在任何一种情况下,该值都将持续到代码重置为止。它只在程序中声明变量时才有所不同。

  • 关于Watch窗口和变量<out of context>,在VBA IDE中添加Watch时,需要将上下文指定为<all procedures><all modules>。否则,仅当调试器在所选模块中停止并且在所选过程中停止时,才会评估Watch变量。

答案 1 :(得分:0)

在函数内创建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声明,因为它可能会导致意外错误(more here)

Dim b1 As New Scripting.Dictionary