Richard
asked on
VB6 using 2 dictionaries with same class
I have a Class Questions which includes the following properties:
1) The Question - String
2) The QuestCode - String
3) PAQuest - Boolean
4) QuestAns - Boolean
5) The QuestID - Long
I instance an object
Set oQst = New clsQuestions
I load the object from an SQL datatable
I then add the object into a dictionary (dicQuestions)
dicQuestions.Add CStr(oQst.QuestID), oQst
Based on the value of PAQuest - if true I also add the object into another dictionary (dicPAQuestions)
If oQst.PAQuest Then
dicPAQuestions.Add CStr(oQst.QuestID), oQst
End If
After loading all the questions, I stop (breakpoint) and run the following
Debug.Print "Main: " & dicQuestions.Item("3217"). Question
Debug.Print "Main: " & dicQuestions.Item("3217"). QuestAns
Debug.Print "PA: " & dicPAQuestions.Item("3217" ).Question
Debug.Print "PA: " & dicPAQuestions.Item("3217" ).QuestAns
dicQuestions.Item("3217"). QuestAns = True
Debug.Print "Main: " & dicQuestions.Item("3217"). Question
Debug.Print "Main: " & dicQuestions.Item("3217"). QuestAns
Debug.Print "PA: " & dicPAQuestions.Item("3217" ).Question
Debug.Print "PA: " & dicPAQuestions.Item("3217" ).QuestAns
My results are:
Main: Question Number 1
Main: False
PA: Question Number 1
PA: False
' This is where I set the QuestAns in the dicQuestions dictionary to TRUE
Main: Question Number 1
Main: True
PA: Question Number 1
PA: True <<<===== This is the problem
Why is the value in the dicPAQuestions changing?
I need the two dictionaries to be separate - the questions from each get answered at different times, and I need the results (question answered or not) to be kept separate.
1) The Question - String
2) The QuestCode - String
3) PAQuest - Boolean
4) QuestAns - Boolean
5) The QuestID - Long
I instance an object
Set oQst = New clsQuestions
I load the object from an SQL datatable
I then add the object into a dictionary (dicQuestions)
dicQuestions.Add CStr(oQst.QuestID), oQst
Based on the value of PAQuest - if true I also add the object into another dictionary (dicPAQuestions)
If oQst.PAQuest Then
dicPAQuestions.Add CStr(oQst.QuestID), oQst
End If
After loading all the questions, I stop (breakpoint) and run the following
Debug.Print "Main: " & dicQuestions.Item("3217").
Debug.Print "Main: " & dicQuestions.Item("3217").
Debug.Print "PA: " & dicPAQuestions.Item("3217"
Debug.Print "PA: " & dicPAQuestions.Item("3217"
dicQuestions.Item("3217").
Debug.Print "Main: " & dicQuestions.Item("3217").
Debug.Print "Main: " & dicQuestions.Item("3217").
Debug.Print "PA: " & dicPAQuestions.Item("3217"
Debug.Print "PA: " & dicPAQuestions.Item("3217"
My results are:
Main: Question Number 1
Main: False
PA: Question Number 1
PA: False
' This is where I set the QuestAns in the dicQuestions dictionary to TRUE
Main: Question Number 1
Main: True
PA: Question Number 1
PA: True <<<===== This is the problem
Why is the value in the dicPAQuestions changing?
I need the two dictionaries to be separate - the questions from each get answered at different times, and I need the results (question answered or not) to be kept separate.
ASKER
Hi Martin,
I set a break point after all the questions are loaded and dictionaries filled. Then I step through the 9 steps. the first 4 steps show that the QuestAnswered value is False for both dictionaries.
At step 5 I change the value of the QuestAnswered value in the dicQuestions dictionary to TRUE.
dicQuestions.Item("3217"). QuestAnswe red = True
At steps 6 - 9 I check the value of the QuestAnswered value in both dictionaries.
The value in the dicQuestions dictionary is TRUE as expected,
The value in the dicPAQuestions dictionary is also TRUE - very much unexpected.
I'm stepping (F8) and the program goes nowhere else.
I tried entering a watch statement:
dicPAQuestions.Item("3217" ).Question Answered
to break when the value changes
An error is thrown 457 - "This key is already associated with an element of this collection line 510"
490 dicQuestions.Add CStr(oQst.QuestID), oQst
500 If oQst.PAQuestion Then
510 dicPAQuestions.Add CStr(oQst.QuestID), oQst
520 End If
This is in the load method - first time through.
Apparently the watch statement adds some logic which modifies the class.
If I remove the watch statement, the error doesn't happen, the dictionaries get filled with all the data then the program breaks at my breakpoint where I test the value of the QuestionAnswered value as above.
Richard
I set a break point after all the questions are loaded and dictionaries filled. Then I step through the 9 steps. the first 4 steps show that the QuestAnswered value is False for both dictionaries.
At step 5 I change the value of the QuestAnswered value in the dicQuestions dictionary to TRUE.
dicQuestions.Item("3217").
At steps 6 - 9 I check the value of the QuestAnswered value in both dictionaries.
The value in the dicQuestions dictionary is TRUE as expected,
The value in the dicPAQuestions dictionary is also TRUE - very much unexpected.
I'm stepping (F8) and the program goes nowhere else.
I tried entering a watch statement:
dicPAQuestions.Item("3217"
to break when the value changes
An error is thrown 457 - "This key is already associated with an element of this collection line 510"
490 dicQuestions.Add CStr(oQst.QuestID), oQst
500 If oQst.PAQuestion Then
510 dicPAQuestions.Add CStr(oQst.QuestID), oQst
520 End If
This is in the load method - first time through.
Apparently the watch statement adds some logic which modifies the class.
If I remove the watch statement, the error doesn't happen, the dictionaries get filled with all the data then the program breaks at my breakpoint where I test the value of the QuestionAnswered value as above.
Richard
Apparently the watch statement adds some logic which modifies the class.I strongly doubt that that ever happens.
How are your two dictionaries created? I ask because the code is acting like VBA is treating them as the same dictionary.
ASKER
Hi Martin,
In my main declaration I have:
Public dicQuestions As Dictionary
Public dicPAQuestions As Dictionary
Then in my main startup routine I have:
Set dicQuestions = New Dictionary
Set dicPAQuestions = New Dictionary
Then later in my startup routine I call the procedure to load up the dictionaries.
At the beginning of the load method, I clear both dictionaries: dicQuestions.RemoveAll and dicPAQuestions.RemoveAll.
Can you explain why there is an error with the watch statement in place and there is no error when I remove (Delete) the watch statement?
Richard
In my main declaration I have:
Public dicQuestions As Dictionary
Public dicPAQuestions As Dictionary
Then in my main startup routine I have:
Set dicQuestions = New Dictionary
Set dicPAQuestions = New Dictionary
Then later in my startup routine I call the procedure to load up the dictionaries.
At the beginning of the load method, I clear both dictionaries: dicQuestions.RemoveAll and dicPAQuestions.RemoveAll.
I strongly doubt that that ever happens.
Can you explain why there is an error with the watch statement in place and there is no error when I remove (Delete) the watch statement?
Richard
The only reason I can think of is that the watch will slow down processing a tiny bit and maybe doing that results in a duplicate key whereas without the watch the processing is faster and VBA doesn't get the chance to throw the error.
And just for laughs try defining the dictionaries like this
Public dicQuestions As New Dictionary
Public dicPAQuestions As New Dictionary
and comment out the Sets in the main startup routine.
And just for laughs try defining the dictionaries like this
Public dicQuestions As New Dictionary
Public dicPAQuestions As New Dictionary
and comment out the Sets in the main startup routine.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Martin and aikimark,
Sorry about the delay in responding - I have been having Internet connection problems, my ISP is making a change which affects my static IPs and his performance and service!
Martin, I tried revising the way the dictionaries are defined - no change. Is there any advantage to using that syntax vs. my original syntax?
aikimark, I'v been wondering about that, so I'm in the process of setting up a new object for the PADictionary. I'll let you know as soon as I'm done.
A general question along these lines -
At the start of my load method I instance a new clsQuestion object. After using that object, should I set it to Nothing before re-instancing it at the top of the load loop, or should I instance the object before the loop and use the same instance inside the loop?
Thanks for both of your quick replies. Hopefully my ISP will keep things going for me!
Richard
Sorry about the delay in responding - I have been having Internet connection problems, my ISP is making a change which affects my static IPs and his performance and service!
Martin, I tried revising the way the dictionaries are defined - no change. Is there any advantage to using that syntax vs. my original syntax?
aikimark, I'v been wondering about that, so I'm in the process of setting up a new object for the PADictionary. I'll let you know as soon as I'm done.
A general question along these lines -
At the start of my load method I instance a new clsQuestion object. After using that object, should I set it to Nothing before re-instancing it at the top of the load loop, or should I instance the object before the loop and use the same instance inside the loop?
Thanks for both of your quick replies. Hopefully my ISP will keep things going for me!
Richard
I don't think you have to dereference it (set it to nothing). As long as you create/instantiate a new one, it should work the way you want.
ASKER
Hi aikimark,
That did the trick. I created another object for use during the loading of the of the questions. It makes my load twice as long - I load from SQL each value twice:
oQst.Question = fQuestion.Value
and
oPQst.Question=fQuestion.v alue
for each parameter - however only 12 parameters so not too bad.
I'm just starting to get my head around to this OOP stuff and have to think more about references than I did with straight procedural programming.
Anyway, thanks for the quick help.
Richard
That did the trick. I created another object for use during the loading of the of the questions. It makes my load twice as long - I load from SQL each value twice:
oQst.Question = fQuestion.Value
and
oPQst.Question=fQuestion.v
for each parameter - however only 12 parameters so not too bad.
I'm just starting to get my head around to this OOP stuff and have to think more about references than I did with straight procedural programming.
Anyway, thanks for the quick help.
Richard
If you you don't know how to do that then see my article on debugging.