4

I have a dictionary like this:

var dict1 = new Dictionary<(int, int), int);
dict1.add((1,2), 3);

That is serialized to a string using:

var s = JsonConvert.SerializeObject(dict1);
// s = "{\"(1,2)\":\"3\"}";

When trying to deserialize the string using:

var j = JsonConvert.DeserializeObject<Dictionary<(int, int), int>>(s);

I get an error like:

'Could not convert string '(1,2)' to dictionary key type 'System.ValueTuple`2[System.Int32,System.Int32]'. Create a TypeConverter to convert from the string to the key type object.

How can I deserialize my string into a tuple key? Using a custom object or a TypeConverter? If so, how?

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
span
  • 5,405
  • 9
  • 57
  • 115

1 Answers1

6

First, you make yourself a TypeConverter for ValueTuples<T1,T2>

internal class ValueTupleConverter<T1, T2>
   : TypeConverter 
   where T1: struct where T2: struct
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, 
      Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context,
      CultureInfo culture, object value)
    {
        var elements = ((String)value).Split(new[] { '(', ',', ')'},
          StringSplitOptions.RemoveEmptyEntries);

        return (
            JsonConvert.DeserializeObject<T1>(elements.First()), 
            JsonConvert.DeserializeObject<T2>(elements.Last()));
    }
}

(Production code should be made more robust and efficient.)

Then, because you can't do the usual thing of applying the TypeConverter attribute at compile-time, you add it at run-time, once

  TypeDescriptor.AddAttributes(typeof((Int32, Int32)), 
    new TypeConverterAttribute(typeof(ValueTupleConverter<Int32, Int32>)));

Finally, you convert as you were doing

var j = JsonConvert.DeserializeObject<Dictionary<(int, int), int>>(s);
Tom Blodget
  • 20,260
  • 3
  • 39
  • 72
  • Nice, added it to `Program.cs` with some extra error checking and it seems to work flawlessly. – span Feb 10 '18 at 10:13