Convert Dictionary(Of String, Object) to Dictionary(Of String, String) - vb.net

When I try to pass a Dictionary(Of String, Object) to a function parameter that wants a Dictionary(Of String, String) I get the following error:
Unable to cast object of type 'System.Collections.Generic.Dictionary'2[System.String,System.Object]' to type 'System.Collections.Generic.Dictionary'2[System.String,System.String]'.
All of the Object values in the dictionary are strings but the dictionary was declared as String/Object. I would have thought that the system would be able to convert this but since it isn't I need to do it myself.
I looked at the .ToDictionary() prototype method but all of the examples show a list being converted to a dictionary.
I found this question which has an accepted answer for what I want but it's written in C# and I can't figure out the conversion to VB.Net.
Edit 1
Offending code. Obviously boiled down or else I would just simply declare dict1 as string/string in my actual code.
Dim dict1 As New Dictionary(Of String, Object) From {{"key1","value1"}}
SomeFunctionThatExpectsParamToBeDictOfStringString(dict1)
Edit 2
I tried:
SomeFunctionThatExpectsParamToBeDictOfStringString(dict1.ToDictionary(Function(k) k.Key, Function(v) v.Value.ToString()))
but got:
System.MissingMemberException: Public member 'ToDictionary' on type 'Dictionary(Of String,Object)' not found.

This could be the VB.NET version of the C# code you have linked
Dim dic1 As Dictionary(Of String, Object) = New Dictionary(Of String, Object)
dic1.Add("A", "B")
Dim dic2 As Dictionary(Of String, String) = dic1.ToDictionary(Function(k) k.Key,
Function(v) v.Value.ToString())

Related

VB.Net Why does my dictionary need to be explicitly declared in order to use select?

Using VB.Net with MVC5.
I have a dictionary:
Dim Filter as New Dictionary(Of String, Object)
' the key's value is another dictionary
Filter.Add("customParams", New Dictionary(Of String, String) From {{"k1","v1"}, {"k2","v2"}, {"k3","v3"}})
and I am trying to convert the Filter("customParams") value, which is a Dictionary(Of String, String), to a delimited string, "k1=v1, k2=v2, k3=v3"
This doesn't work:
Dim kvString As String = String.Join(", ", Filter("customParams").Select(Function(x) x.Key & "=" + x.Value).ToArray())
I get this exception:
Public member 'Select' on type 'Dictionary(Of String,String)' not
found.
But if I explicitly declare a new variable for the Dictionary(Of String,String) and use that instead of Filter("customParams") then this works:
Dim customParams As Dictionary(Of String, String) = Filter("customParams")
Dim kvString As String = String.Join(", ", customParams.Select(Function(x) x.Key & "=" + x.Value).ToArray())
Why doesn't it work the other way? The exception itself says that it's working with a Dictionary(Of String, String)
By default, VB.Net allows late binding (OPTION STRICT OFF). Late binding is the equivalent of dynamic in C# and means the runtime looks up the method to call by name and the compiler does not type checking or validation. Only public members can be accessed by late binding, so extension (friend) methods such as Select are not available. This is automatic for object variables in VB.Net. customParams has a (non-object) assigned type and thus uses early binding.

Nested Dictionary System.NullReferenceException in VB.net [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I have scoured the internet looking for a solution to this problem but the null exception remains. Basically I am getting System.NullReferenceException error when attempting to add values to a nested dictionary.
Here is my code.
Public Dict1 as New Dictionary(Of Integer, Dictionary(Of String, String))() 'Tried with and without()
Sub CreateDict(Length As Integer)
Dim key As Integer
Dim CmdName As String
Dim CmdValue As String
key = 0
CmdName = "UnusedCmd"
CmdValue = "NotAFolder,NotAFolder,NotAFolder,NotAFolder,NotAFolder,Read"
While key <= Length
Dim CmdDict As New Dictionary(Of String, String)
CmdDict.Add("Name", CmdName) 'Method 1 of Adding
CmdDict.Add("Command", CmdValue) 'Method 1 of Adding
'CmdDict("Name") = CmdName 'Method 2 of Adding Both seem to work as evidenced by msgbox
'CmdDict("Command") = CmdValue 'Method 2 of Adding Both seem to work as evidenced by msgbox
MsgBox(CmdDict("Name")) ' Returns UnusedCmd
MsgBox(CmdDict("Command"))' Returns NotAFolder,NotAFolder,NotAFolder,NotAFolder,NotAFolder,Read
MsgBox(key) 'Returns 1
Dict1.Add(key, CmdDict)
key = key + 1
CmdDict = Nothing 'Error Occurs whether or not this is commented out
End While
End Sub
Note this code was adapted from my original project which was in VBA for outlook 2016. I am trying to readapt this code to be an outlook addin.
I have tried replacing the "As" terms with "=" and I have also tried
Dim CmdDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
For both dictionaries but this didn't work. I have tried everything that I can think of / find please help.
Could it have something to do with it being a public dictionary? I saw someone else using a public dicitonary and they're solution was to add new which I new I had to do otherwise no object would be created.
EDIT:
I just tried a regular dictionary as a public variable and it failed as well. So it appears to have nothing to do with being Nested. I will continue looking into the public object issue.
EDIT 2:
Just Tried adding Dict1 to Public Class Still not working.
Public Class GlobalVariables
Public Shared Dict1 As Dictionary(Of Integer, Dictionary(Of String, String)) = New Dictionary(Of Integer, Dictionary(Of String, String))
End Class
After doing this Dict1 was updated to GlobalVariables.Dict1
EDIT 3:
This code is within a VSTO Addin that I am creating based on macros that I wrote in Outlook VBA. I am using Visual Studio Community 2015. The location of the code is as follows
Edit 4:
Duplicate? I agree I thought that this was a duplicate answer as well but I couldn't anywhere else where the answer was to move the Create Object from Public to within a Sub for a public variable. But the rest of the question is very similar to others agreed.
Try it this way.
Public Dict1 as Dictionary(Of Integer, Dictionary(Of String, String))
Sub CreateDict(Length As Integer)
Dict1 = New Dictionary(Of Integer, Dictionary(Of String, String))
<Rest of your code>
End Sub

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 }

How do I write this lambda select method in VB.net?

For I've tried this:
Dim exampleItems As Dictionary(Of String, String) = New Dictionary(Of String, String)
Dim blah = exampleItems.Select (Function(x) New (x.Key, x.Value)).ToList 'error here
But I'm getting a syntax error and all the examples that I've seen are in C#.
This would be:
Dim blah = exampleItems.Select (Function(x) New With { .Key = x.Key, .Value = x.Value }).ToList
For details, see Anonymous Types. (Depending on usage, you might also want Key or Value to be flagged with the Key keyword.)
That being said, Dictionary(Of TKey, Of TValue) already is an IEnumerable(Of KeyValuePair(Of TKey, Of TValue), so you can also just do:
Dim blah = exampleItems.ToList
And you'll have a list of KeyValuePair, which has a Key and Value property already. This really means there's no need to make the anonymous type.

Compile error while adding items to nested dictionary

I am trying to created nested dictionary variable like the below, But I get compile error stating that it needs "}" at line where I am adding items (line #2) to my nested dictionary.
What Am I missing here? Thanks.
Dim myNestedDictionary As Dictionary(Of String, Dictionary(Of String, Integer)) = New Dictionary(Of String, Dictionary(Of String, Integer))()
myNestedDictionary.Add("A", New Dictionary("A", 4)())
In VS 2008 and .net 3.5 you cannot declare and initialize a Dictionary in one line, so you have to do:
Dim myNestedDictionary As New Dictionary(Of String, Dictionary(Of String, Integer))()
Dim lTempDict As New Dictionary(Of String, Integer)
lTempDict.Add("A", 4)
myNestedDictionary.Add("A", lTempDict)
To retrieve the an item use the following:
Dim lDictionaryForA As Dictionary(Of String, Integer) = myNestedDictionary.Item("A")
Dim lValueForA As Integer = lDictionaryForA.Item("A")
The value in lValueForA should be 4.
You need to specify the type of dictionary you are creating when you add the records:
myNestedDictionary.Add("A", New Dictionary(Of String, Integer))
or otherwise pass an existing Dictionary(Of String, Integer) as the inside-dictionary argument (when adding key/value pairs to the external dictionary).
(BTW, Your external dictionary is a dictionary who's Keys are Strings and Values are Dictionaries (Of String, Integer), is this really what you wanted?)
In C# you can do that:
var myNestedDictionary = new Dictionary<string, Dictionary<string, int>>() {{ "A", new Dictionary<string, int>() { { "A", 4 } } }};
You can do it in VB 2010 as well, using the From keyword, but it doesn't compile in VS 2008. It will compile in VB 2010, no matter which .NET Framework you target. I've tried 2.0, 3.5 and 4.0.
Dim myNestedDictionary = New Dictionary(Of String, Dictionary(Of String, Integer))() From {{"A", New Dictionary(Of String, Integer) From {{"A", 4}}}}