2

I am using Newtonsoft to parse some JSon into a .Net type. The json contains an array of arrays called 'data'. I would like to make each array within the data array it's own type, but am unsure how to do this.

Hopefully the code below demonstrates this.

    public class TheData
    {
        [JsonProperty(PropertyName = "data")]
        public List<object> dataItems { get; set; }
    }

Usage:

        string json =
            "{\"data\":[[\"20180511\",1094391],[\"20180504\",1097315],[\"20180427\",1100221],[\"20180420\",1094455],[\"20180413\",1093023]]}";

        var myObj = JsonConvert.DeserializeObject<TheData>(json);

This works ok, however, I would like to change the type of dataItems from List to List as below:

    public class TheData
    {
        [JsonProperty(PropertyName = "data")]
        public List<DataItem> dataItems { get; set; }
    }

public class DataItem
{
    public string deldate { get; set; }
    public int value { get; set; }
}

However, this results in an exception:

Newtonsoft.Json.JsonSerializationException occurred
  HResult=-2146233088
  Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'CE.FOTools.Feeds2.EIA.DataItem' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'data[0]', line 1, position 10.

The error message suggests my desired outcome may not be possible, but can anyone suggest how to correct this? I have no control over the JSON format (unles I operate on the string once it is retrieved). I'm using .Net 4.5 if that makes any difference.

1 Answer 1

2

I think the least obtrusive way is to use custom converter. For example:

class DataItemConverter : JsonConverter<DataItem> {
    public override void WriteJson(JsonWriter writer, DataItem value, JsonSerializer serializer) {
        // if item can be null - handle that
        writer.WriteStartArray();
        writer.WriteValue(value.deldate);
        writer.WriteValue(value.value);
        writer.WriteEndArray();
    }

    public override DataItem ReadJson(JsonReader reader, Type objectType, DataItem existingValue, bool hasExistingValue, JsonSerializer serializer) {
        var ar = serializer.Deserialize<List<object>>(reader);
        // perform some checks for length and data types, omitted here
        var result = new DataItem();
        result.deldate = (string) ar[0];
        result.value = Convert.ToInt32(ar[1]);
        return result;
    }
}

Then specify that this converted should be used by decorating your type:

[JsonConverter(typeof(DataItemConverter))]
public class DataItem {
    public string deldate { get; set; }
    public int value { get; set; }
}

And after that it should work as you expect.

If generic JsonConverter<> is not available in your Json.NET version - use non-generic one:

class DataItemConverter : JsonConverter {
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        var item = (DataItem) value;
        // if null is possible - handle that
        writer.WriteStartArray();
        if (item != null) {
            writer.WriteValue(item.deldate);
            writer.WriteValue(item.value);
        }

        writer.WriteEndArray();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var ar = serializer.Deserialize<List<object>>(reader);
        // perform some checks for length and data types, omitted here
        var result = new DataItem();
        result.deldate = (string) ar[0];
        result.value = Convert.ToInt32(ar[1]);
        return result;
    }

    public override bool CanConvert(Type objectType) {
        return objectType == typeof(DataItem);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Many thanks for your answer. I think I may be using an older version of Newtonsoft as this does not compile. I will spend a bit of time upgrading and report back.
@GinjaNinja I've updated answer with version which should work in older versions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.