https://stackoverflow.com/questions/38357864/how-to-conditionally-deserialize-json-object-based-on-another-json-property/

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;	

using NUnit.Framework; // Throws NUnit.Framework.AssertionException

    // https://stackoverflow.com/questions/38357864/c-sharp-how-to-conditionally-deserialize-json-object-based-on-another-json-pro
    internal class IntToBoolConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteValue(((bool)value) ? "1" : "0");
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var token = JToken.Load(reader);
            if (token.Type == JTokenType.Boolean)
                return (bool)token;
            var val = (int)token;
            return val != 0;
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(bool) || objectType == typeof(bool?);
        }
    }

    public class ActionTypeConverter : StringEnumConverter
    {
        public ActionTypeConverter()
            : base()
        {
            this.CamelCaseText = true;
        }
    }

    public abstract class ActionResult
    {
    }

	// Add subtypes of ActionResult corresponding to each different type of result.
    public class OpenActionResult : ActionResult
    {
        public string property1 { get; set; }
        public string property2 { get; set; }
        public DateTime? property3 { get; set; }
        public string property4 { get; set; }
        public bool property5 { get; set; }
    }

    [JsonConverter(typeof(ActionConverter))]
    public class Action
    {
        readonly static Dictionary<Type, System.Type> typeToSystemType;
        readonly static Dictionary<System.Type, Type> systemTypeToType;

        static Action()
        {
            typeToSystemType = new Dictionary<Type, System.Type>
            {
                { Type.Open, typeof(OpenActionResult) },
				// Add additional dictionary entries corresponding to each different subtype of ActionResult
            };
            systemTypeToType = typeToSystemType.ToDictionary(p => p.Value, p => p.Key);
        }

        public static Type SystemTypeToType(System.Type systemType)
        {
            return systemTypeToType[systemType];
        }

        public static System.Type TypeToSystemType(Type type)
        {
            return typeToSystemType[type];
        }

		// Add enum values for Type corresponding to each different subtype of ActionResult
        public enum Type
        {
            Open,
            Close,
            Remove,
            Delete,
            Reverse,
            Alert,
            ScaleInOut,
            Nothing
        }

        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("active")]
        [JsonConverter(typeof(IntToBoolConverter))]
        public bool Active { get; set; }

        [JsonProperty("type")]
        [JsonConverter(typeof(ActionTypeConverter))]
        public Type ActionType { get; set; }

        [JsonProperty("result")]
        public ActionResult Result { get; set; }
    }

    class ActionConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var obj = JObject.Load(reader);
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
            var action = existingValue as Action ?? (Action)contract.DefaultCreator();

            // Remove the Result property for manual deserialization
            var result = obj.GetValue("Result", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();

            // Populate the remaining properties.
            using (var subReader = obj.CreateReader())
            {
                serializer.Populate(subReader, action);
            }

            // Process the Result property
            if (result != null)
                action.Result = (ActionResult)result.ToObject(Action.TypeToSystemType(action.ActionType));

            return action;
        }

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

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

    public static class JsonExtensions
    {
        public static JToken RemoveFromLowestPossibleParent(this JToken node)
        {
            if (node == null)
                return null;
            var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
            if (contained != null)
                contained.Remove();
            // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
            if (node.Parent is JProperty)
                ((JProperty)node.Parent).Value = null;
            return node;
        }
    }

    class TestClass
    {
        static string GetJson()
        {
            var json = @"{
    ""name"":""test1"",
    ""id"":""aa0832f0508bb580ce7f0506132c1c13"",
    ""active"":""1"",
    ""type"":""open"",
    ""result"":{
        ""property1"":""buy"",
        ""property2"":""123.123"",
        ""property3"":""2016-07-16T23:00:00"",
        ""property4"":""768"",
        ""property5"":true
     }
}";
            return json;
        }

        public static void Test()
        {
            var json = GetJson();

            Console.WriteLine("Original JSON: ");
            Console.WriteLine(json);

            var action = JsonConvert.DeserializeObject<Action>(json);

            var json2 = JsonConvert.SerializeObject(action, Formatting.Indented);

            Console.WriteLine("Re-serialized JSON: ");
            Console.WriteLine(json2);

            if (JToken.DeepEquals(JToken.Parse(json), JToken.Parse(json2)))
            {
                Console.WriteLine("Original and re-serialized JSON are equivalent.");
            }
            else
            {
                throw new InvalidOperationException("Original and re-serialized JSON are NOT equivalent.");
            }

            var action2 = JsonConvert.DeserializeObject<Action>(json2);

            var json3 = JsonConvert.SerializeObject(action, Formatting.Indented);

            Console.WriteLine("Re-re-serialized JSON: ");
            Console.WriteLine(json3);
        }
    }

	public class Program
	{
		public static void Main()
		{
			Console.WriteLine("Environment version: " + Environment.Version);
			Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Namespace, typeof(JsonSerializer).Assembly.FullName);
			Console.WriteLine();

			try
			{
				TestClass.Test();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Failed with unhandled exception: ");
				Console.WriteLine(ex);
				throw;
			}
		}
	}
;