https://stackoverflow.com/questions/53391878 - Version 4

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
					
public class Program
{
	public static void Main()
	{
        string json = @"
        [
          {
            ""FirstName"": ""Jane"",
            ""LastName"": ""Doe"",
            ""Birthday"": ""1988-10-06T00:00:00""
          },
          {
            ""FirstName"": ""Joe"",
            ""LastName"": ""Schmoe"",
            ""Birthday"": null
          }
        ]";

        RootModelConverter converter = new RootModelConverter();
        RootModel model = JsonConvert.DeserializeObject<RootModel>(json, converter);
		
        model.Addresses.Add(new Address
        {
            Id = 1,
            Street = "123 Main Street",
            City = "Birmingham",
            State = "AL",
            PostalCode = "35201",
            Country = "USA"
        });
        foreach (var person in model.People)
        {
            person.AddressId = 1;
        }

        json = JsonConvert.SerializeObject(model, Formatting.Indented);
        Console.WriteLine(json);
        Console.WriteLine();
		
		model = JsonConvert.DeserializeObject<RootModel>(json, converter);
		foreach (var person in model.People)
		{
			Address addr = model.Addresses.FirstOrDefault(a => a.Id == person.AddressId);
		    Console.Write(person.FirstName + " " + person.LastName);
			Console.WriteLine(addr != null ? " lives in " + addr.City + ", " + addr.State : "");
		}
	}
}

public class RootModelConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(RootModel);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        RootModel model = new RootModel();
        if (token.Type == JTokenType.Array)
        {
            // we have a Version 3 or earlier model, which was just a list of people.
            model.People = token.ToObject<List<Person>>(serializer);
            model.Addresses = new List<Address>();
            return model;
        }
        else if (token.Type == JTokenType.Object)
        {
            // Check that the version is something we are expecting
            string version = (string)token["Version"];  // case sensitive!
            if (version == "4")
            {
                serializer.Populate(token.CreateReader(), model);
                return model;
            }
            else
            {
                throw new JsonException("Unexpected version: " + version);
            }
        }
        else
        {
            throw new JsonException("Unexpected token: " + token.Type);
        }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public class RootModel
{
    public int Version { get { return 4; } }
	public List<Person> People { get; set; }
	public List<Address> Addresses { get; set; }
}

public class Person
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public DateTime? Birthday { get; set; }
	public int AddressId { get; set; }

	// This property is here to support transitioning from the Version 2 model to Version 3
	[JsonProperty]
	private string Name
	{
		set
		{
			if (value != null)
			{
				string[] parts = value.Split(' ');
				if (parts.Length > 0) FirstName = parts[0];
				if (parts.Length > 1) LastName = parts[1];
			}
		}
	}
}

public class Address
{
	public int Id { get; set; }
	public string Street { get; set; }
	public string City { get; set; }
	public string State { get; set; }
	public string PostalCode { get; set; }
	public string Country { get; set; }
}
;