0

In my class, I have an enum definition as followed:

public enum ChangeType { 
  [EnumMember(Value ="Added")]
  Added,
  [EnumMember(Value = "Removed")]
  Removed,
  [EnumMember(Value = "Updated")]
  Updated 
}

And in the class definition, I have a property:

public 
  Dictionary<string, (ChangeType changType, string oldValue, string newValue)> 
  PropertyChanges { get; set; }

Requirements:

  1. When converting to JSON, changeType should be in text, not number
  2. Tuple should be converted w/ the name of the items instead of Item1, Item2 and Item3

What I have tried:

  • As for the enum, I tried putting the JsonConverter(typeof(StringEnumConverter))] in front of the property (no go)
  • Cannot any recommendation about the named tuples

Question:

Can I achieve the above without writing a custom converter to convert the whole class?

Thanks!

Johnny Wu
  • 1,297
  • 15
  • 31
  • How do you serialize instance of your dictionary? – Guru Stron Aug 12 '20 at 23:11
  • 1
    Also "Tuple should be converted w/ the name of the items instead of Item1, Item2 and Item3" can't be achieved cause your tuple is actually `ValueTuple` and does not actually have `changType`, `oldValue`, `newValue` members. You will need to create class/struct for that. – Guru Stron Aug 12 '20 at 23:16

2 Answers2

2

The names of ValueTuple keys basically don't exist after compilation, except for in some attributes, so the type info that the serializer gets doesn't contain the names.

So you'll have to use a class to control the serialized names, instead of that ValueTuple.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

It's actually not as bad as I thought... JsonConvert.SerializeObject() already has already done a pretty good job serializing the Dictionary<>, so all I have to do is to help Json to interpret the enum and the tuple.

First, I create a class called CustomTupleConverter that implements JsonConverter<(ChangeType changeType, string oldValue, string newValue)>.

In the implementation of WriteJson(), I have the following:

writer.WriteStartObject();
writer.WritePropertyName("Action");
writer.WriteValue(value.changeType.ToString());
writer.WritePropertyName("OldValue");
writer.WriteValue(value.oldValue.ToString());
writer.WritePropertyName("NewValue");
writer.WriteValue(value.newValue.ToString());
writer.WriteEndObject();

When invoking the JsonConvert.SerializeObject(), I simply add the instantiation of my converter to the call:

JsonConvert.SerializeObject(cc, Formatting.Indented, new CustomTupleConverter());

That's it.

Johnny Wu
  • 1,297
  • 15
  • 31
  • 2
    But now this will be invoked for _any_ `(ChangeType, string, string)` tuple, regardless of its member names within `cc`. It will also print "Action" as property name, even if you later decide to rename it. Or how do you implement `CanWrite`? This may not be what you want. Also, creating a `public class Change { public ChangeType Action { get; set;} public string OldValue { get;set; } public string NewValue { get; set; } }` is way less code and more portable than this solution. – CodeCaster Aug 13 '20 at 11:18
  • 1
    @CodeCaster...this for the recommendation...we are so deep in the rabbit hole w/ the tuple at this moment, converting it w/ a struct and class doesn't seem feasible. To answer your question about CanWrite(): since I am using JsonConverter<>, overriding CanWrite() is not required since it will only work with the specific value tuple. I have to agree with you that making the tuple a struct or a class will definitely make my life easier. :) – Johnny Wu Aug 13 '20 at 12:56