简体   繁体   English

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

[英]VBA dictionary <out of context> after Sub is run

I am trying to run the following code to create a dictionary that will then be used in a function to assign the functions parameter values depending on the dictionary key. 我正在尝试运行以下代码来创建字典,然后将其用于函数中,以根据字典键分配函数参数值。

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

Although this worked initially, after I temporarily changed the Sub to Static Sub it stopped working. 尽管此方法起初很有效,但在我将Sub临时更改为Static Sub之后,它停止了工作。 Changing it back to what it was in its last working condition has not fixed the problem. 将其改回其最后的工作状态仍无法解决问题。 Restarting VBA and running the code as a new module also haven't worked. 重新启动VBA并将代码作为新模块运行也没有用。

While debugging I can see in the Watch window that the dictionary b1 is created as it should, however after the Sub finishes it takes the value "out of context". 调试时,我可以在“监视”窗口中看到按需创建的字典b1,但是在Sub完成后,它将取值为“上下文无关”。 It doesn't make any sense, and it's now driving me crazy! 这没有任何意义,现在让我发疯! Can anyone help? 有人可以帮忙吗?

A couple of points: 要点:

  • Add a reference to the Microsoft Scripting Runtime library; 添加对Microsoft脚本运行时库的引用; this will allow you to use the actual types, instead of plain Object: 这将允许您使用实际类型,而不是普通对象:

     Public b1 As Scripting.Dictionary 
  • You could initialize the dictionary using the New syntax: 可以使用New语法初始化字典:

     Public b1 As New Scripting.Dictionary 

    although this will only create the dictionary; 尽管这只会创建字典; it won't fill it; 它不会填满它; which brings us the the next point. 这给我们带来了下一点。

  • AFAIK, in VBA there is no constructor method for modules. AFAIK,在VBA中没有模块的构造方法。 So you'll have to verify that the dictionary has been filled, and perhaps test for initialization as well, before you try to use it: 因此,在尝试使用字典之前,您必须验证字典是否已填充,并可能还要测试初始化​​:

     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 
  • The Static keyword won't make a difference here. Static关键字在这里不会有所作为。 According to the documentation , the Static keyword on a Function or Sub : 根据文档 ,在FunctionSub上使用Static关键字:

    indicates that the Sub procedure's local variables are preserved between calls. 指示在调用之间保留Sub过程的局部变量。 The Static attribute doesn't affect variables that are declared outside the Sub , even if they are used in the procedure. 即使在过程中使用了Static属性, Static属性也不会影响在Sub外部声明的变量。

    and in this case the b1 variable has been declared outside of the Sub . 在这种情况下, b1变量已在Sub外部声明。

    Using the Static statement to declare module-level variables (such as b1 ) will also have no effect -- in either case the value will last until the code is reset. 使用Static语句声明模块级变量(例如b1 )也不会起作用-在这两种情况下,值都将持续到重置代码为止。 It only makes a difference when declaring variables within a procedure. 它仅在过程中声明变量时有所不同。

  • Regarding the Watch window and the variables <out of context> , when you add a Watch in the VBA IDE, you need to specify the context as <all procedures> and <all modules> . 关于“监视”窗口和变量<out of context> ,在VBA IDE中添加Watch时,需要将上下文指定为<all procedures><all modules> Otherwise, the Watch variable will only be evaluated when the debugger is stopped within the selected module, and within the selected procedure. 否则,仅当调试器在所选模块内和所选过程内停止时,才会评估Watch变量。

Create a Static Dictionary inside the function. 在函数内部创建一个Static Dictionary The dictionary will be populated the first time you use the function but after that the values will be retained and the relevant code skipped. 首次使用该函数时,将填充该词典,但此后将保留值,并跳过相关代码。

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

As others have pointed out, it's usually better to early-bind your variables. 正如其他人指出的那样,通常最好尽早绑定变量。 Which means if you know you want a Dictionary object, avoid declaring a Object first and then converting it to a Dictionary when you can just declare it as a Dictionary right away. 这意味着如果你知道你想要一个Dictionary对象,避免声明一个Object ,然后再将其转换为一个Dictionary时,你可以声明为一个Dictionary的时候了。 To do this you need to include the reference to the Scripting Runtime Library and use: 为此,您需要包括对脚本运行时库的引用,并使用:

Dim b1 As Scripting.Dictionary
Set b1 = New Scripting.Dictionary

Do not use the single As New statement below because it can cause unwanted errors (more here) 不要使用下面的单个As New语句,因为它可能导致不必要的错误(更多信息请参见此处)

Dim b1 As New Scripting.Dictionary

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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