Maritim
Maritim

Reputation: 2159

C#: Deserializing JSON when one field can be different types

I am communicating with an API that returns JSON containing either true, false or an array of string arrays. I wish to deserialize this JSON and store the boolean value, if there is one, in a class field called Success of data type bool, and the array, if there is one, in a field called Result of a custom data type.

What is the best to go about achieving this?

Some JSON:

[
    {"status":"ok","result":true},
    {
        "status":"ok",
        "result":
        [
            {"name":"John Doe","UserIdentifier":"abc","MaxAccounts":"2"}
        ]
    }
]

My Result class:

class Result
{
    string Name,
    string UserIdentifier,
    string MaxAccounts
}

Class for communicating with the Api:

class Api
{
    public string Status { get; set; }
    public Result[] Result { get; set; }
    public bool Success { get; set; }
}

Upvotes: 3

Views: 3279

Answers (2)

yavuz
yavuz

Reputation: 332

create and arraylist using Api and Results objects. I have just tried this and it works.

        var api = new Api();
        var result = new Result();
        api.Status = "ok";
        api.Success = true;
        result.Name = "John Doe";
        result.UserIdentifier = "abc";
        result.MaxAccounts = "2";
        api.Result = new Result[1];
        api.Result[0] = result;
        var arrayList = new ArrayList() { new {api.Status, api.Success}, 
                        new { api.Status, api.Result} };
        var json = JsonConvert.SerializeObject(arrayList, Formatting.Indented);

Upvotes: 0

Darin Dimitrov
Darin Dimitrov

Reputation: 1039080

With JSON.NET you could write a custom JSON converter. For example you could have the following objects:

public class Root
{
    public string Status { get; set; }
    public Result Result { get; set; }
}

public class Result
{
    public bool? Value { get; set; }
    public Item[] Items { get; set; }
}

public class Item
{
    public string Name { get; set; }
    public string UserIdentifier { get; set; }
    public string MaxAccounts { get; set; }
}

and your JSON will be deserialized to a Root[].

Here's how the custom JSON converter may look like:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Boolean)
        {
            return new Result
            {
                Value = (bool)reader.Value,
            };
        }

        return new Result
        {
            Items = serializer.Deserialize<Item[]>(reader),
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // If you want to support serializing you could implement this method as well
        throw new NotImplementedException();
    }
}

and then:

class Program
{
    static void Main()
    {
        var json = 
        @"[
            {
                ""status"": ""ok"",
                ""result"": true
            },
            {
                ""status"": ""ok"",
                ""result"": [
                    {
                        ""name"": ""John Doe"",
                        ""UserIdentifier"": ""abc"",
                        ""MaxAccounts"": ""2""
                    }
                ]
            }
        ]";

        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new ResultConverter());
        Root[] root = JsonConvert.DeserializeObject<Root[]>(json, settings);
        // do something with the results here
    }
}

Upvotes: 4

Related Questions