I am trying to deserialize a JSON object that has an array of unnamed arrays and am running into some problems. The code I am running to test:
var json = "{ \"Triangles\": [[1337],[1338],[1339]]}";
var mesh = JsonConvert.DeserializeObject<Mesh>(json);
and the classes of interest:
public class Mesh
{
[JsonProperty]
public Triangle[] Triangles { get; set; }
}
public class Triangle
{
[JsonProperty]
public int[] Indices { get; set; }
}
Running the code and trying to deserialize using Newtonsoft I get the following exception:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ConsoleApp1.Triangle' 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 'triangles[0]', line 1, position 17.
Adding [JsonArray] to the Triangle class results in the following exception though:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Cannot create and populate list type ConsoleApp1.Triangle. Path 'Triangles[0]', line 1, position 17.
What am I missing?
Edit: An important thing I obviously forgot to mention was that I would like to deserialize it into the classes listed in the post for semantic reasons. That is, although deserializing Triangles into List<List<int>>
or int[][]
would work I would very much prefer to not do so.
With a Custom converter. Deserialise the array to a JArray and select from there.
var json = "{ \"Triangles\": [[1337,1400],[1338],[1339]]}";
var mesh = JsonConvert.DeserializeObject<Mesh>(json);
public class Mesh
{
[JsonConverter(typeof(MyConverter))]
public Triangle[] Triangles { get; set; }
}
public class Triangle
{
[JsonProperty]
public int[] Indices { get; set; }
}
public class MyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
var result =
JArray.Load(reader)
.Select(x =>
new Triangle { Indices = x.Select(y => (int)y).ToArray() }
);
return result.ToArray();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
The way your classes are currently set up. JSON.NET will try to deserialize Triangle[]
as an array of json object. The most simple solution is to change the type of Triangles
to int[,]
to make it a 2d array. If you want to keep using Triangle[]
you need to use a custom JsonConverter
.
Edit: Since you want to keep the Triangle class you need a custom JsonConverter
class.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class TriangleJsonConverter : JsonConverter<Triangle>
{
// Called when Triangle is written
public override void WriteJson(JsonWriter writer, Triangle value, JsonSerializer serializer)
{
// Uses JsonSerializer to write the int[] to the JsonWriter
serializer.Serialize(writer, value.Indices);
}
// Called when Triangle is read
public override Triangle ReadJson(JsonReader reader, Type objectType, Triangle existingValue, bool hasExistingValue, JsonSerializer serializer)
{
// Reads a json array (JArray) from the JsonReader
var array = JArray.Load(reader);
// Creates a new Triangle.
return new Triangle
{
// converts the json array to an int[]
Indices = array.ToObject<int[]>()
};
}
}
To tell JSON.NET to use the TriangleJsonConverter
you need to apply JaonArray
to the Triangles
field instead of JsonProperty
.
public class Mesh
{
[JsonArray(ItemConverterType = typeof(TriangleJsonConverter))]
public Triangle[] Triangles { get; set; }
}
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.