2

I've been struggling to deserialize a Dictionary with Enum Tuple keys in Json.Net. The main problem is that the deserializer can't convert the values back to the specified Enum Tuple whether it's the Enum's string or integer representation in the Json.

I've tried these solutions but none of the worked:

  1. https://stackoverflow.com/a/59310390
  2. https://gist.github.com/SteveDunn/e355b98b0dbf5a0209cb8294f7fffe24

Tried to write my own Custom Converter, the WriteJson part works, but I can't even stop the ReadJson function with breakpoints to see what happens inside.

I'd be happy to get some help with the issue. Maybe somebody already has a solution.

The JSON looks like this:

{
   "DictionaryProperty":{
      "(EnumType1Value1, EnumType2Value1)":"New",
      "(EnumType1Value1, EnumType2Value1)":"Old",
      "(EnumType1Value2, EnumType2Value1)":"Newer",
      "(EnumType1Value2, EnumType2Value2)":"Older"
}

This is the error I get:

"Could not convert string '(EnumType1Value1, EnumType2Value1)' to dictionary key type 'System.ValueTuple`2[EnumType1,EnumType2]'"

This is the custom converter I wrote:

public class CustomDictionaryConverter : JsonConverter<Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>>
{
    public override void WriteJson(JsonWriter writer, Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, ((Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>)value).ToList());
    }

    public override Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> ReadJson(
        JsonReader reader
        , Type objectType
        , Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> existingValue
        , bool hasExistingValue
        , JsonSerializer serializer)
    {
        Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> tempdict = new Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>();

        var temp = serializer.Deserialize<Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>[]>(reader)[0];

        tempdict = (Dictionary<(EnumType1 Enum1, EnumType2  Enum2), string>)temp;
        return tempdict;
    }
}
10
  • What is the json to deserialize? Is it fixed or can you work on it? If you can insert an intermediate step, I would use a simple string as a key in the dictionary, using a simple concatenation and a split to convert back and forth from the Enum Tuple. Commented Jan 14, 2021 at 14:21
  • 1
    @Charlieface , The burden of minimal reproducible example is usually on the person who brings up the question. Commented Jan 14, 2021 at 14:34
  • 4
    The issue is that (Enum,Enum) is a complex key -- one not convertible to a string. Since dictionaries are serialized as JSON objects with the key becoming the property name, Json.NET doesn't know how to serialize such a dictionary, as is explained in the docs. Commented Jan 14, 2021 at 14:41
  • 1
    Your options are to implement a type converter for (Enum,Enum) as shown in Not ableTo Serialize Dictionary with Complex key using Json.net, or serialize the dictionary as an array as shown in How can I serialize/deserialize a dictionary with custom keys using Json.Net?. Commented Jan 14, 2021 at 14:41
  • 5
    Tried to write my own Custom Converter, the WriteJson part works, but I can't even stop the ReadJson function with breakpoints to see what happens inside. -- then please show a minimal reproducible example. Commented Jan 14, 2021 at 14:43

1 Answer 1

1

A bit manual (and lacking decent error checking), but works for your specified json both serializing & deserializing

public class CustomDictionaryConverter : JsonConverter<Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>>
{
    public override void WriteJson(JsonWriter writer, Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        foreach(var kv in value)
        {
            writer.WritePropertyName($"({kv.Key.Enum1.ToString()},{kv.Key.Enum2.ToString()})");
            writer.WriteValue(kv.Value);
        }
        writer.WriteEndObject();
    }

    public override Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> ReadJson(
        JsonReader reader
        , Type objectType
        , Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> existingValue
        , bool hasExistingValue
        , JsonSerializer serializer)
    {
        Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string> tempdict = new Dictionary<(EnumType1 Enum1, EnumType2 Enum2), string>();
        JObject jObject = JObject.Load(reader);
        foreach(var kv in ((IEnumerable<KeyValuePair<string, JToken>>)jObject)) 
        {
            var keys = kv.Key.Replace("(","").Replace(")","").Split(",");
            var key1 = Enum.Parse<EnumType1>(keys[0]);
            var key2 = Enum.Parse<EnumType2>(keys[1]);
            var value = kv.Value.ToString();
            tempdict.Add((key1,key2),value);
        }
        return tempdict;
    }
}

Live example: https://dotnetfiddle.net/w85HgK

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.