Reputation: 43
Im trying to parse JSON which is I believe object array. I can parse simple single JSON with JObject.Parse but this one gives me headache.
{
"2": {
"num": 5,
"average": 10,
"state": true,
"id": 2,
"buy": 10,
"name": "name"
},
"6": {
"num": 5,
"average": 10,
"state": true,
"id": 6,
"buy": 20,
"name": "name"
}
}
I had idea but dont know how to deal with numbers before bracket. Its always the same as "id".
I tried to use Newtonsoft.Json something like this:
List<Items> objlis = (List<Items>)Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(List<Items[]>));
However it says that "the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly."
Upvotes: 3
Views: 2209
Reputation: 116990
It looks as though the sending system chose to serialize a sparse list as a JSON object where the object names are the list indices, rather than as a JSON array. But Json.NET maps JSON arrays from and to c# lists so your deserialization to List<Items>
fails with the exception message the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
The simplest way to deserialize such a JSON object is as a dictionary such as Dictionary<string, Items>
or SortedDictionary<int, Items>
as is shown in this question, e.g.:
var dict = JsonConvert.DeserializeObject<SortedDictionary<int, Items>>(json);
If you specifically require the JSON to be deserialized as a list, you can write a custom JsonConverter
to do the mapping:
public class ListToDictionaryConverter<T> : JsonConverter where T : class
{
public override bool CanConvert(Type objectType)
{
return typeof(List<T>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var list = existingValue as List<T> ?? (List<T>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
if (reader.TokenType == JsonToken.StartArray)
serializer.Populate(reader, list);
else if (reader.TokenType == JsonToken.StartObject)
{
var dict = serializer.Deserialize<Dictionary<int, T>>(reader);
foreach (var pair in dict)
list.SetOrAddAt(pair.Key, pair.Value, default(T));
}
else
{
throw new JsonSerializationException(string.Format("Invalid token {0}", reader.TokenType));
}
return list;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var list = (IList<T>)value;
writer.WriteStartObject();
for (int i = 0; i < list.Count; i++)
{
// Omit null values.
if (list[i] == default(T))
continue;
writer.WritePropertyName(((JValue)i).ToString());
serializer.Serialize(writer, list[i]);
}
writer.WriteEndObject();
}
}
public static class ListExtensions
{
public static void SetOrAddAt<T>(this IList<T> list, int index, T value, T defaultValue = default(T))
{
if (list == null)
throw new ArgumentNullException("list");
list.EnsureCount(index + 1, defaultValue);
list[index] = value;
}
public static void EnsureCount<T>(this IList<T> list, int count, T defaultValue = default(T))
{
if (list == null)
throw new ArgumentNullException("list");
int oldCount = list.Count;
if (count > oldCount)
{
for (int i = oldCount; i < count; i++)
list.Add(defaultValue);
}
}
}
Then use it like:
var objlis = JsonConvert.DeserializeObject<List<Items>>(json, new ListToDictionaryConverter<Items>());
Sample fiddle.
Upvotes: 0
Reputation: 62
You can built table like following from Json and then call to datagridview
List<User> allusers = JsonConvert.DeserializeObject<List<User>>(jsonString);
public static DataTable MakeDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for(int i = 0 ; i < props.Count ; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Upvotes: 1
Reputation: 62
var result = JsonConvert.DeserializeObject<List<JsonResult>>(input);
dataGridView.DataSource = result;
Upvotes: 0