https://stackoverflow.com/questions/67044973

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
					
public class Program
{
	public static void Main()
	{
		string newerTakeoffJson = @"
        {
          ""$type"": ""TakeoffEvent, MyAssembly"",
          ""TimeOfTakeoff"": ""2021-04-11T15:00:00.000Z"",
          ""Airport"": {
            ""Name"": ""KLAX"",
            ""Runway"": ""25L""
          }
        }";
		DeserializeAndDump(newerTakeoffJson, "newer JSON format - Takeoff");

		string newerLandingJson = @"
        {
          ""$type"": ""LandingEvent, MyAssembly"",
          ""TimeOfLanding"": ""2021-04-11T15:30:00.000Z"",
          ""Airport"": {
            ""Name"": ""KLAX"",
            ""Runway"": ""25R""
          }
        }";
		DeserializeAndDump(newerLandingJson, "newer JSON format - Landing");

		string legacyTakeoffJson = @"
        {
          ""$type"": ""TakeoffEvent, MyAssembly"",
          ""TimeOfTakeoff"": ""2021-04-12T16:05:00.000Z"",
          ""AirportName"": ""KLAX"",
          ""AirportRunway"": ""25L""
        }";
		DeserializeAndDump(legacyTakeoffJson, "legacy JSON format - Takeoff");


		string legacyLandingJson = @"
        {
          ""$type"": ""LandingEvent, MyAssembly"",
          ""TimeOfLanding"": ""2021-04-12T16:35:00.000Z"",
          ""AirportName"": ""KLAX"",
          ""AirportRunway"": ""25R""
        }";
		DeserializeAndDump(legacyLandingJson, "legacy JSON format - Landing");
	}
	
	static void DeserializeAndDump(string json, string message)
	{
		// in .NET Fiddle the assembly name is random, so we have to manually replace it in the JSON sample. 
		// You should not need to do this step in your own code.
		json = json.Replace("MyAssembly", typeof(BaseEvent).Assembly.GetName().Name);

		Console.WriteLine("---- " + message + " ----");
		Console.WriteLine(json);
		Console.WriteLine();

		var settings = new JsonSerializerSettings
		{
			TypeNameHandling = TypeNameHandling.Objects,
			Converters = new List<JsonConverter> { new EventConverter() },
		};

		var baseEvent = JsonConvert.DeserializeObject<BaseEvent>(json, settings);
		if (baseEvent is TakeoffEvent takeoff)
		{
			Console.WriteLine("Time of Takeoff: " + takeoff.TimeOfTakeoff);
		}
		else if (baseEvent is LandingEvent landing)
		{
			Console.WriteLine("Time of Landing: " + landing.TimeOfLanding);
		}
		Console.WriteLine("Airport/Runway: " + baseEvent.Airport.Name + " " + baseEvent.Airport.Runway);
		Console.WriteLine();
	}
	
}

class Airport
{
    public string Name { get; set; }
    public string Runway { get; set; }
}

class BaseEvent
{
    public Airport Airport { get; set; }
}

class TakeoffEvent : BaseEvent
{
    public DateTime TimeOfTakeoff { get; set; }
}

class LandingEvent : BaseEvent
{
    public DateTime TimeOfLanding { get; set; }
}

class EventConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(BaseEvent).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);

        string type = (string)obj["$type"];
        BaseEvent baseEvent;
        if (type.Contains(nameof(TakeoffEvent)))
        {
            baseEvent = new TakeoffEvent();
        }
        else
        {
            baseEvent = new LandingEvent();
        }
        serializer.Populate(obj.CreateReader(), baseEvent);

        if (baseEvent.Airport == null)
        {
            baseEvent.Airport = new Airport
            {
                Name = (string)obj["AirportName"],
                Runway = (string)obj["AirportRunway"]
            };
        }
        return baseEvent;
    }

    public override bool CanWrite => false;

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