0

我正在尝试反序列化一个 JSON 对象,该对象具有一组未命名的数组并且遇到了一些问题。我正在运行测试的代码:

var json = "{ \"Triangles\": [[1337],[1338],[1339]]}";
var mesh  = JsonConvert.DeserializeObject<Mesh>(json);

和感兴趣的类别:

public class Mesh
{
    [JsonProperty]
    public Triangle[] Triangles { get; set; }
}

public class Triangle
{
    [JsonProperty]
    public int[] Indices { get; set; }
}

运行代码并尝试使用 Newtonsoft 反序列化我得到以下异常:

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.

将 [JsonArray] 添加到 Triangle 类会导致以下异常:

Newtonsoft.Json.JsonSerializationException
  HResult=0x80131500
  Message=Cannot create and populate list type ConsoleApp1.Triangle. Path 'Triangles[0]', line 1, position 17.

我错过了什么?

编辑:我显然忘记提到的一件重要的事情是,出于语义原因,我想将其反序列化为帖子中列出的类。也就是说,尽管将 Triangles 反序列化为List<List<int>>int[][]会起作用,但我非常希望不这样做。

4

2 回答 2

0

使用自定义转换器。将数组反序列化为 JArray 并从中选择。

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();
    }
}
于 2019-11-04T11:04:13.677 回答
-1

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; }
}
于 2019-11-04T10:08:50.713 回答