5

I'm trying to create a dictionary of dictionaries in VBS, and I can get it to work; however, it seems that my sub level dictionary is being accessed by reference instead of by value?

I tried this:

Dim s, fso, f, ts, str, fRead, line, i, dictElements, dictionary, screenItem
Set s = CreateObject("System.Text.StringBuilder")
Set fso = CreateObject("Scripting.FileSystemObject")
Set dictElements = CreateObject("Scripting.Dictionary")
Set dictionary = CreateObject("Scripting.Dictionary")

'add elements to dictionary
dictElements.Add "Name", "MyName"
dictElements.Add "Setpoint", 100.0
dictElements.Add "Process Value", 80.6

'Create Data Structure
dictionary.Add "DigitalInputOne", dictElements
dictionary.Add "DigitalInputTwo", dictElements

'test dictionary
dictionary("DigitalInputTwo")("Name")= "Hello"
dictionary("DigitalInputTwo")("Setpoint")= 40.123
HmiRuntime.Screens("Home").ScreenItems("Text field_1").Text = dictionary ("DigitalInputOne")("Name")
HmiRuntime.Screens("Home").ScreenItems("Text field_2").Text = dictionary("DigitalInputOne")("Setpoint")
HmiRuntime.Screens("Home").ScreenItems("Text field_3").Text = dictionary("DigitalInputOne")("Process Value")

HmiRuntime.Screens("Home").ScreenItems("Text field_4").Text = dictionary("DigitalInputTwo")("Name")
HmiRuntime.Screens("Home").ScreenItems("Text field_5").Text = dictionary("DigitalInputTwo")("Setpoint")
HmiRuntime.Screens("Home").ScreenItems("Text field_6").Text = dictionary("DigitalInputTwo")("Process Value")

When I change one of the values it changes all of the values, which makes me think my elements dictionary is by reference. Is there a way to make this happen by value? I want each sub dictionary to be different.

1 Answer 1

5

You only have

Set dictElements = CreateObject("Scripting.Dictionary")

once so you are only creating one subdictionary -- and are setting two keys to point to that one subdictionary. Instead, do the following:

Set dictElements = CreateObject("Scripting.Dictionary") 'create first sub-dict
dictionary.Add "DigitalInputOne", dictElements
Set dictElements = CreateObject("Scripting.Dictionary") 'create second sub-dict
dictionary.Add "DigitalInputTwo", dictElements

VBScript has reference-counting based garbage collection. When you add the first dictionary to the top-level dictionary, the top level dictionary now maintains a reference to it. Thus, when you set dictElements equal to a second dictionary, the original dictionary is kept alive by the top-level dictionary, hence it isn't garbage-collected.

Sign up to request clarification or add additional context in comments.

10 Comments

Will this allow me to create a template, or is there a better way to do that? Most of my subdictionaries will be the same, only with different values.
I would write a sub which, when passed a dictionary, initializes it in a certain way. Then follow the 3-step process: 1) create the dictionary, 2) run the initialization sub on it, 3) assign it to the top-level dictionary.
I wanted to use dictElements basically like a data type. I did this, and it works Set dictionary("DigitalInputOne") = CreateObject("Scripting.Dictionary") Set dictionary("DigitalInputTwo") = CreateObject("Scripting.Dictionary") For Each item In dictionary For Each element In dictElements dictionary(item).Add element, dictElements(element) Next Next but I don't think it's very good. I can't use classes because I'm doing this in WinCC.
I would use a Class for this and have a Dictionary of Class objects.
@Lankymart You are correct that a custom class provides a good solution to OP's problem. If you flesh out the idea and add it as a second answer I would gladly upvote it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.