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. 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.
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". 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; 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:
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. 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. According to the documentation , the Static
keyword on a Function
or Sub
:
indicates that the
Sub
procedure's local variables are preserved between calls. TheStatic
attribute doesn't affect variables that are declared outside theSub
, even if they are used in the procedure.
and in this case the b1
variable has been declared outside of the 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. 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>
. Otherwise, the Watch variable will only be evaluated when the debugger is stopped within the selected module, and within the selected procedure.
Create a Static
Dictionary
inside the function. 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. 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)
Dim b1 As New Scripting.Dictionary
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.