简体   繁体   中英

C# how to determine which object to deserialize to

I'm calling a Web API that is returning a JSON payload. One of the fields is sometimes a boolean and sometimes it's a JSON object itself.

Is there a way to determine if I have a class I'm deserializing (document) or the field that is sometimes just a Boolean? When I get the Boolean it throws an error.

I supposed I could try one class and if there is an error try another but seems like there should be a better way to do this. Example JSON would be

{
  "field1":"value1",
  "field2":false
}

VS

{
  "field1":"value1",
  "field2":
  {
    "field21":"value21",
    "field22":"value22"
  }
}
[TestClass]
public class UnitTest2
{
    [TestMethod]
    public void Test()
    {
        var json1 = "{\"field1\":\"value1\",\"field2\":true}";
        var deserializedWithBool = JsonConvert.DeserializeObject<ObjectJson>(json1);

        var json2 = "{\"field1\":\"value1\",\"field2\": { \"field21\" : \"value21\", \"field22\" : \"value22\"}}";
        var deserializedWithObject = JsonConvert.DeserializeObject<ObjectJson>(json2);

        Assert.AreEqual(true, deserializedWithBool.field2.field2BoolResult);
        Assert.AreEqual("value21", deserializedWithObject.field2.field21);
    }
}

public class ObjectJson
{
    public string field1 { get; set; }

    [JsonConverter(typeof(FieldJsonConverter))]
    public FieldResult field2 { get; set; }
}

public class FieldResult
{
    public bool? field2BoolResult { get; set; }
    public string field21 { get; set; }
    public string field22 { get; set; }
}

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Boolean)
        {
            return new FieldResult() { field2BoolResult  = (bool)(JValue)token };
        }
        else if (token.Type == JTokenType.Object)
        {
            return token.ToObject<FieldResult>();
        }

        throw new InvalidOperationException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

Use json.net then create Custom jsonConverter example above:

https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm

You could also use a generic type to store Field2...

    public class MyClassBase<T>
    {
        public string Field1 { get; set; }
        public T Field2 { get; set; }
    }

    public class Field
    {
        public string Field21 { get; set; }
        public string Field22 { get; set; }
    }

    public class TestJsonDeserialise
    {
        public void Run()
        {
            var json1 = @"{
          'field1':'value1',
          'field2':
          {
          'field21':'value21',
          'field22':'value22'
          }
        }";

            var json2 = @"{
          'field1':'value1',
          'field2':false 
        }";

            var json = json2;
            var field2 = JObject.Parse(json)["field2"];

            object myClass = null;
            switch (field2.Type)
            {
                case JTokenType.Object:
                    myClass = GetMyClass<MyClassBase<Field>>(json);
                    break;
                case JTokenType.Boolean:
                    myClass = GetMyClass<MyClassBase<bool>>(json);
                    break;
            }

            switch (myClass)
            {
                case MyClassBase<Field> fieldResult:
                    //When FieldResult then do stuff
                    Console.WriteLine("You got an Object");
                    break;
                case MyClassBase<bool> boolResult:
                    //You got a bool back
                    Console.WriteLine("You got a bool");
                    break;
            }
        }

        public T GetMyClass<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }
    }

You should make your own implementation of the JsonConverter class and use the attribute [JsonConverter(typeof(YourJsonConverter))]

You can then apply your own implementation for deserialization of the property.

You can override the ReadJson method to examine the type of object, and act accordingly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM