[CSHARP-44] Dictionary objects fail as long as the key is not of type string (or some base type) Created: 18/Jun/10  Updated: 02/Jun/11  Resolved: 19/Jun/10

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Minor - P4
Reporter: nisbus Assignee: Craig Wilson
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

All



 Description   

This method:

public object CreateDictionary(Document document)

{ return document.ToDictionary(pair => (TKey)Convert.ChangeType(pair.Key, typeof(TKey)), pair => (TValue)pair.Value); }

Will fail for all Dictionary types that have a key of any value other than string.
This is because when the key of a dictionary is of some class type the key will be stored as the name of the class instead of a document.

To replicate this behavior just create an object that contains a Dictionary<SomeCLRObject, SomeCLRObject> and save it.
When you try to load it again you will get an error on CreateDictionary stating that (TKey)Convert.ChangeType(pair.Key, typeof(TKey) cannot be performed as string will not be cast to SomeCLRObject.

I attached a sample to the SortedList bug that shows this behavior.
http://jira.mongodb.org/browse/CSHARP-43



 Comments   
Comment by Robert Stam [ 02/Jun/11 ]

This JIRA ticket refers to an older community driver. The official driver supports serializing Dictionaries where the keys are not strings. It serializes them as an array of key/value pairs stored in 2-element arrays. But see the newly created JIRA ticket for a minor improvement to this:

https://jira.mongodb.org/browse/CSHARP-238

Comment by Chris Nicola [ 01/Jun/11 ]

One way this limitation could be worked around is to serialize this as an array of KeyValuePari<T1,T2> objects like so: [{key:

{ /* some key object */ }

, value:

{ /* some value object */ }

]. I believe custom serialization for the .NET driver is flexible enough for someone to implement this, though I could be wrong.

Comment by Craig Wilson [ 19/Jun/10 ]

This is unsupportable feature and is most likely impossible to implement.

Comment by Craig Wilson [ 19/Jun/10 ]

Understood. This is ultimately going to be a limitation imposed by Json and it will be fairly difficult (if not impossible) to work outside these constraints for an arbitrarily complex key. I don't think the choice of using an IDictionary<,> is the wrong choice however. It is exactly what it is. A hashed set of values based on a key.

You are free to implement IDictionaryAdapter to support some custom types of solutions, but ultimately keys will have to be serialized and deserialized as strings. It's as simple as that.

I'm going to close this issue as won't resolve. We can reopen it if necessary.

Comment by nisbus [ 19/Jun/10 ]

Since Dictionaries in C# don't have this limitation I wonder if mapping them to a JSON dictionary is the correct way to handle this.
Maybe Dictionaries should be mapped to two List<T>s instead and deserialized back to dictionary?

I have my doubt's about creating an implicit string operator since you would also have to deserialize it back to an object from the string which would be a major headache when using complex objects as keys.

I'm guessing that a string in Json has some limitations as to length and so using an IConvertible<string> for large object graphs as key would not work either.

Consider this class:

class SomeClassUsingDictionary
{
public Dictionary<DeepAbstractObjectGraphObject, string> MyFunkyDictionary

{get;set;}
}

abstract class DeepAbstractObjectGraphObject : IComparable
{
public List<AnotherComplexObject> SomeList {get;set;}

}

I don't see any obvious way to serialize SomeClassUsingDictionary other than converting the MyFunkyDictionary to List<DeepAbstractObjectGraphObject> and List<string> for storage and then deserializing it back to Dictionary.
This would need to have a discriminator _d? with the name of the dictionary and a specification on whether this was the Keys or the Values list i.e.

{ _d : "MyFunkyDictionary, Key" }

My two cents

Comment by Craig Wilson [ 19/Jun/10 ]

Thanks for reporting. This is always going to be an issue and there isn't a lot we can do about it. MongoDb stores everything in Json. The Json spec says that all keys are strings. Therefore, in the driver, we have to serialize both to a string and from a string. If you tried this with an integer as the key, it would work because there is a conversion from int to string and vice versa implicity.

So, I'd like to know if creating an implicit string operator on SomeCLRObject would allow this to work. Alternatively, we could always look for IConvertible<string> or something to handle this.

Please comment back with your thoughts.

Generated at Wed Feb 07 21:35:39 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.