DateTime as Object in dictionary - vb.net

I have read here that a dictionary (of string, object) can hold multiple variable types. However, in the function below, endTime does not appear to get assigned. The line Console.Write(lobjWaveOutList(0)("endTime")) in the code below gives me the error 'the given key was not present in the dictionary'.
Private lobjWaveOutList As New List(Of Dictionary(Of String, Object))()
Public Sub addIndex(waveOut As Object, endTime As DateTime)
Console.WriteLine("endTime:")
Console.WriteLine(endTime)
lobjWaveOutList.Add(New Dictionary(Of String, Object)() From {{"waveOut", waveOut}})
lobjWaveOutList.Add(New Dictionary(Of String, Object)() From {{"endTime", endTime}})
Console.Write(lobjWaveOutList(0)("endTime"))
End Sub
I called the addIndex function with the following parameters:
waveouts.addIndex(New WaveOut(), DateTime.Now.AddSeconds(10))

lobjWaveOutList(0)("endTime") will not work because it is accessing the first dictionary in the list, which only contains a "waveOut" item. The "endTime" item is in the second dictionary in the list. To get that one, you'd need to do this:
Console.Write(lobjWaveOutList(1)("endTime"))
As Neolisk pointed out, it would seem more appropriate, based on your example, to simply have a single dictionary, containing multiple items, rather than a list of dictionaries, each only containing a single item.

As you have a list of Dictonary "endtime" is here: lobjWaveOutList(1)("endTime")

Related

How can i change the values in a dictionary that are inside another dictionary?

I've come here after hours of looking on the internet. Nothing comes close to what I am trying to achieve.
I have this:-
Private Portfolio_Client_List As New Dictionary(Of String, Dictionary(Of String, Double))
which I then add keys to like the following:-
Portfolio_Client_List.Add(str.Substring(6, 5).Trim, New Dictionary(Of String, Double))
then I add keys to the other dictionary like the below:-
For Each pair As KeyValuePair(Of String, Dictionary(Of String, Double)) In Portfolio_Client_List
pair.Value.Add("Office Collections", 0.00)
pair.Value.Add("Home Collections", 0.00)
Next
Now I want to update the values in the Office Collections and Home Collections keys values.
How can I do so? I thought it would be as simple as:-
For Each pair As KeyValuePair(Of String, Double) In Portfolio_Client_List("key")
pair.Value += Head_Office_Payments
Next
However it just gives me the readonly error. Is there any way to do this, or am I wasting my time?
No, KeyValuePairs are immutable structs, so you can't modify them, Value is readonly.
But this works (you want to add Head_Office_Payments to the old value):
Dim dict As Dictionary(Of String, Double) = Portfolio_Client_List("key")
For Each key As String In dict.Keys.ToList()
dict(key) += Head_Office_Payments
Next
Note that you need the dict.Keys.ToList(creates a new list) because you can't modify the collection while enumerating, setting the Value of a dictionary increases it's version number which invalidates the iterator. That's why i prefer this one-liner LINQ solution:
dict = dict.ToDictionary(Function(kv) kv.Key, Function(kv) kv.Value + Head_Office_Payments)

Passing Enums as parameters - as a dictionary(of string, enum) (VB 2012)

This might be impossible or a bit wrong headed, however in WinForms I've got combo boxes that need populating with specific options. The project uses about 10 different forms, all with similar but slightly different functionality: hence why I didn't use just one form and hide/show controls as appropriate.
Now I made a simple dictionary of options and fed the values with an Enum. Now I realise I've got duplicate code and would like to consolidate it. The option sets are date order and name order, but I've got one or two more to list.
This is what I've tried but cannot pass the dictionary into:
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As Dictionary(Of String, [Enum]))
nameorder.Items.Clear()
For Each item In Options
nameorder.Items.Add(item)
Next
nameorder.DisplayMember = "Key"
nameorder.ValueMember = "Value"
End Sub
Property NameOrderOptions As New Dictionary(Of String, PersonList.orderOption) From {{"First Name", PersonList.orderOption.FirstName},
{"Last Name", PersonList.orderOption.LastName},
{"Room Number", PersonList.orderOption.RoomNumber}}
Property DateOrderOptions As New Dictionary(Of String, OrderDate) From {{"Newest First", OrderDate.NewestFirst}, {"Oldest First", OrderDate.OldestFirst}}
I've tried a few variations with Type and [enum].getnames etc but I can't pass the differing dictionary types in at all - I think I've overcomplicated the whole business by now but feel I'm missing an elegant solution. Shortly I'll either convert back to string matching alone, or just have functions per box type - evil duplication but I can move on.
Am I right in thinking there is a nicer way to do this? Unless I just define some kind of global resource for the options maybe-but globals are bad right?
Edit: Fixed thanks to Steven. In case anyone finds it useful OR better yet, anyone can critique and make nicer, here's the module code that all the forms can use to generate their options.
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As IDictionary)
nameorder.Items.Clear()
For Each item In Options
nameorder.Items.Add(item)
Next
nameorder.DisplayMember = "Key"
nameorder.ValueMember = "Value"
End Sub
Property NameOrderOptions As New Dictionary(Of String, orderOption) From {{"First Name", orderOption.FirstName},
{"Last Name", orderOption.LastName},
{"Room Number", orderOption.RoomNumber}}
Property DateOrderOptions As New Dictionary(Of String, OrderDate) From {{"Newest First", OrderDate.NewestFirst}, {"Oldest First", OrderDate.OldestFirst}}
Property personStatusOptions As New Dictionary(Of String, personStatus) From {{"Active", personStatus.Active},
{"InActive", personStatus.InActive},
{"All", personStatus.All}}
Public Sub BuildComboBoxes(ListBoxes As Dictionary(Of ComboBox, IDictionary))
For Each pair In ListBoxes
BuildOrderOptions(pair.Key, pair.Value)
Next
End Sub
Public Enum OrderDate
OldestFirst
NewestFirst
End Enum
Public Enum personStatus
Active
InActive
All
End Enum
Public Enum orderOption
None
FirstName
LastName
RoomNumber
End Enum
And here's the way I've got one form using it - yes, I could have had a bunch of parameters or multiple function calls: I just like having a single object giving me a single parameter to pass on.
BuildComboBoxes( New Dictionary ( Of ComboBox , IDictionary ) From {{NameOrder, NameOrderOptions},
{DateOrder, DateOrderOptions},
{personStatus, PersonStatusOptions}})
You just need to change your method to accept any IDictionary object rather than a specific type of dictionary:
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As IDictionary)
When you are using generics, such as Dictionary(Of TKey, TValue), the generic type is not really a type at all. You can think of it like a template for any number of specific types. So each time you use a generic type using different type parameters, they are entirely different and incompatible types. For instance:
' This works fine because both d1 and d2 are exactly the same type
Dim d1 As New Dictionary(Of String, String)()
Dim d2 As Dictionary(Of String, String) = d1
' This will not compile because d1 and d2 are completely different types
Dim d1 As New Dictionary(Of String, Integer)()
Dim d2 As Dictionary(Of String, Boolean) = d1
As you have found out, even if you try to use a base class as the generic type parameter, the two are still incompatible. So, even though Stream is the base class for MemoryStream, you still cannot do this:
' This will not compile because d1 and d2 are completely different types
Dim d1 As New Dictionary(Of String, MemoryStream)()
Dim d2 As Dictionary(Of String, Stream) = d1

List of Dictionary Arrays

Hit a wall, and can't find much in docs.
I have two dictionaries, and I'd like to put them in a list.
Dim listOfDictionaries As List(Of Dictionary(Of String, String))
is not working.
Am I correct in assuming that once I get this dimmed, I can .add the conventional way?
Details (EDIT)
When trying to listOfDictionaries.Add(dictionaryIWantToAdd), I get "value of type '1-dimensional array system.collection.generic.dictionary(of string, string)' cannot be converted to 'system.collection.generic.dictionary(of string, string)'
Solution
Helps to put the () on the end an array. :P
The conventional way is:
Dim both = New List(Of Dictionary(Of String, String))()
both.Add(Dictionary1)
both.Add(Dictionary2)
The error says it all. You are trying to add an array of dictionaries to the list, but the add method only takes a single dictionary, not an array of them. Either fix it so you are only passing in a single dictionary:
Dim myDictionary As Dictionary(Of String, String)
' ...
listOfDictionaries.Add(myDictionary)
Or use the AddRange method to add all the dictionaries in the array at once:
Dim myArrayOfDictionaries() As Dictionary(Of String, String)
' ...
listOfDictionaries.AddRange(myArrayOfDictionaries)
I tend to favour single-line solutions when it's something straightforward like this, making use of the From keyword.
Dim listOfDictionaries = New List(Of Dictionary(Of String, String)) From { dictionary1, dictionary2 }

nested dictionaries

I've got a nested dict like:
Public collectionMain As New Dictionary(Of String, Dictionary(Of String, String))
When inserting a new item:
collectionMain.Add(node.SelectSingleNode("key").InnerText.Trim, collectionSub)
collectionSub.Clear()
On the add my collectionSub is filled with key & values.
But when calling clear, the collectionMain.value is empty.
How can i keep the collectionMain dictionary value?
The collectionSub needs to be cleared, it's in a loop for filling.
thank you
You need to create a New Dictionary(Of String, String) for each value.
Whenever you add a new dictionary item, you will have to declare a new sub-dictionary for that key:
collectionMain.Add(node.SelectSingleNode("key").InnerText.Trim, _
New Dictionary(Of String, String))
The collectionSub variable really should not exist since every key in collectionMain has it's own dictionary.
Do not clear collectionSub. Don't forget that you are adding reference of Dictionary(Of String, String) - collectionSub. If you want to clear that object then you must have to create a "clone" (deep copy) of collectionSub. Take a look at SO thread - What is the best way to clone/deep copy a .NET generic Dictionary?

Can't get a List(Of <my class>) from a Dictionary in .NET?

I have a Dictionary with key of type UInteger and the value is List(Of Session) where the (Public) class Session contains a couple of variables and a constructor (Public Sub New(...)).
Some of the variables in my Session class is:
Private count As Integer
Private StartDate As Date
Private Values As List(Of Integer)
and a couple of methods like:
Friend Sub Counter(ByVal c as Integer)
count += c
End Sub
There is no problem to add values to the Dictionary:
Dim Sessions As New List(Of Session)
Dim dict As New Dictionary(Of Integer, List(Of Sessions))
then some code to fill up a couple of Session objects in Sessions (not shown here) and then:
dict.Add(17, Sessions) ''#No problem
Sessions.Clear()
Sessions = dict(17) ''#This doesn't return anything!
The Sessions object is empty even if the code doesn't returned any error.
Is my class Session to compex to be stored in a Dictionary?
That's because the Sessions variable is a reference to the data, so when you add it to the dictionary, the one in the dictionary is pointing to the same thing. So when you do Sessions.Clear() you clear the actual data and since both the references point at the same place, neither of them now hold the data.
If you actually want to have two different copies of the data, this discussion might be helpful.
These lines seem fishy to me:
Dim Sessions As New List(Of Session)
' Your Sessions variable has the same name as a class? '
Dim dict As New Dictionary(Of Integer, Sessions)
' You are adding a List(Of Session) to a Dictionary(Of UInteger, Sessions)? '
' This could only be legal if List(Of Session) derived from your Sessions class '
' (which is obviously not true). '
dict.Add(17, Sessions)
It's also confusing what exactly you mean here:
Sessions.Clear()
Sessions = dict(17) 'This does not return anything!'
By "doesn't return anything," do you mean it returns Nothing or an empty List(Of String)? In the latter case, that's expected: you just cleared the very list you're talking about. In the former case, that is very strange, and we'll need more details.