Alexandre
Alexandre

Reputation: 148

would you write a custom Json.net Serializer/Derserializer?

I am starting to think I need to write a custom converter in Json.net because so far the regular converter is not cutting it. I have a class Game

class Game  
    {
        [JsonProperty]
        public int Edition { get; private set; }
        [JsonProperty]
        public string Name
    {
        get
        {
            return NameType.ToString();
        }
        private set
        {
            name = value;
        }
    }

    [JsonProperty]
    public string Date { get; private set; }

    [JsonConverter(typeof(StringEnumConverter))]  
    public GameType NameType { get; private set; } //enum

    public List<Question> Questions { get; private set; } //yes, Question is serializable

public Game(string Date, GameType t, int num, List<Question> q)
    {
        this.Date = Date;
        this.NameType = t;
        this.Edition = num;
        this.Questions = q;
    }

That Serializes to the correct Json, but won't deserialize correctly. the Json looks like this:

{
 "Edition": 1,
  "Name": "Regular",
  "Date": "2016",
  "NameType": "Regular",
  "Questions": [
    {
      "QuestionNumber": "1",
      "Round": 1,
      "Body": "1. A couple paragraphs",
      "Answer": " answers"
    },
  ]
}

But when deserialized, it comes out as:

Date"2016", Edition "1", Name "None", NameType "None", Questions null

did I do something wrong in deserializing like this:

 Game g = JsonConvert.DeserializeObject<Game>(File.ReadAllText(path));

or is this a situation which warrants writing a custom serializer?

I have yet to find a question currently answered that deals with something like this bug I have hit, and according to the documentation on Json.net most of the weird edge cases that need a custom serializer are non-IEnumerables and DateTimes.

Upvotes: 1

Views: 71

Answers (1)

dbc
dbc

Reputation: 116785

It looks as though you are trying to create a class with some immutable properties, namely Edition, Date, NameType. Furthermore, one of then, NameType, needs a JsonConverter applied to be serialized properly by Json.NET. You can serialize and deserialize such a class by giving it one single constructor with the necessary properties passed in as arguments provided the argument names are the same as the c# property names, modulo case. You can apply the attribute [JsonConverter(typeof(StringEnumConverter))] to the appropriate argument as well as to the corresponding property, however if it is not applied the converter from the corresponding property will be used as long as the property and parameter have identical declared types.

class Game  
{
    public Game(int edition, string date, [JsonConverter(typeof(StringEnumConverter))] GameType nameType)
    {
        this.Edition = edition;
        this.Date = date;
        this.NameType = nameType;
        this.Questions = new List<Question>();
    }

    public int Edition { get; private set; }

    [JsonIgnore]
    public string Name
    {
        get
        {
            return NameType.ToString();
        }
    }

    public string Date { get; private set; }

    [JsonConverter(typeof(StringEnumConverter))]  
    public GameType NameType { get; private set; } //enum

    public List<Question> Questions { get; private set; } //yes, Question is serializable
}

Sample fiddle.

If your class has more than one constructor, mark the one that has all the required immutable properties with [JsonConstructor], e.g.:

    public Game(int edition, string date, [JsonConverter(typeof(StringEnumConverter))] GameType nameType) 
        : this(edition, date, nameType, new List<Question>())
    {
    }

    [JsonConstructor]       
    public Game(int edition, string date, [JsonConverter(typeof(StringEnumConverter))] GameType nameType, List<Question> questions)
    {
        this.Edition = edition;
        this.Date = date;
        this.NameType = nameType;
        this.Questions = questions;
    }

Upvotes: 1

Related Questions