2

I have a web service in vb.net which returns json-formatted data. One of the data items can take a number of different types of values: Boolean, String, Dictionary(of String, String) or Dictionary(Of String, Object) The latter is to allow flexible lists of data to be returned. Each then has an itemType and DataType specified in the response so the thirtd party knows what to expect. This has worked fine.

However, I am now getting the following error trying to return a Dictionary(Of String, Dictionary(Of String, List(Of String))):

Value of type 'System.Collections.Generic.Dictionary(Of String, System.Collections.Generic.Dictionary(Of String, System.Collections.Generic.List(Of String)))' cannot be converted to 'System.Collections.Generic.Dictionary(Of String, Object)'.

It is quite happen to take a Dictionary(Of String, Dictionary(Of String, String)) but not a Dictionary(Of String, Dictionary(Of String, List(Of String))). I am very confused - I though pretty much anything could convert to Object? Why can a Dictionary(Of String, String) convert to oject but not a Dictionary(Of String, List(Of String))?

I can get round it by doing the following:

Dim Bar As New Dictionary(Of String, Dictionary(Of String, List(Of String)))
' Add stuff to bar here

Dim Foo As New Dictionary(Of String, Object)
For Each Row As KeyValuePair(Of String, Dictionary(Of String, List(Of String))) In Bar
    Foo.Add(Row.Key, New Dictionary(Of String, Object))
    For Each Item As KeyValuePair(Of String, List(Of String)) In Row.Value
        Foo(Row.Key).add(Item.Key, Item.Value)
    Next
Next

but I don't understand why I need to. is there something I am missing that could cause a problem later and can anyone explain what sorts of objects cannot be cast to Object?

Adam
  • 6,539
  • 3
  • 39
  • 65

1 Answers1

3

I think the feature you are looking for is co-variance. IDictionary(Of TKey, TValue) is not co-variant. This means that Dictionary(Of String, String) cannot be converted directly to a less specific type like IDictionary(Of String, Object).

IEnumerable(Of T) is co-variant however (as of .Net 4.0), So you can convert List(Of String) to IEnumerable(Of Object).

Of course all classes like Dictionary(TKey, TValue) ultimately derive from Object, so you can do this:

Dim myObject As New Dictionary(Of String, String)
Dim myDictionary As New Dictionary(Of String, Object)
myDictionary.Add("Test1", myObject)

and you can also do this:

Dim myObject As New Dictionary(Of String, Dictionary(Of String, List(Of String)))
Dim myDictionary As New Dictionary(Of String, Object)
myDictionary.Add("Test2", myObject)

However, you cannot do what you have claimed to have done here:

Dim myDictionary1 As New Dictionary(Of String, Dictionary(Of String, String))
Dim myDictionary2 As IDictionary(Of String, Object) = myDictionary1

myDictionary1 is an object, so it can be added to myDictionary2 like this (once myDictionary2 is instantiated): myDictionary2.Add("Test3", myDictionary1) but it cannot be converted to type IDictionary(Of String, Object) because IDictionary(TKey, TValue) is not co-variant.

Please see https://stackoverflow.com/a/2149602/1887337 and Eric Lippert's explanation here as to exactly why the dictionary is designed this way: https://stackoverflow.com/a/5636770/1887337

Community
  • 1
  • 1
ThatShawGuy
  • 1,363
  • 1
  • 14
  • 27