json.net error: unexpected token deserializing object

json.net error: unexpected token deserializing object

我有一个包含一些 json 的文件,它是由 json.net:

生成的
[
  {
    "$type": "Dashboard.Gauges.LabelGaugeSeed, Dashboard",
    "Text": "blah",
    "LabelColor": {
      "X": 1.0,
      "Y": 1.0,
      "Z": 1.0,
      "W": 1.0
    },
    "Center": {
      "X": 0.0,
      "Y": 0.0
    },
    "CharacterWidth": 0.05,
    "CharacterHeight": 0.1,
    "LineThickness": 0.01,
    "TextCentering": 0.5
  }
]

反序列化时出现上述错误。谁能找到这个 json 的问题?我 运行 它通过了验证器,它说没问题。

它在 "Center" 之后的 space 上出错:如果我更改 Center 和 LabelColor 属性的顺序,它会在 "LabelColor" 之后以相同的方式出错:

这里是类型的转储:

LabelColor为OpenTK Vector4,Center为OpenTK Vector2,LabelGaugeSeed如下:

public class LabelGaugeSeed : IGaugeSeed
{
    public IGauge Grow()
    {
        return new LabelGauge(this);
    }

    public string Text;
    [JsonConverter(typeof(Vector4Converter))]
    public Vector4 LabelColor;
    [JsonConverter(typeof(Vector2Converter))]
    public Vector2 Center;
    public float CharacterWidth;
    public float CharacterHeight;
    public float LineThickness;
    public float TextCentering;
}

这里是 Vector4Converter:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        reader.Read();
        reader.Read();
        var x = serializer.Deserialize<float>(reader);

        reader.Read();
        reader.Read();
        var y = serializer.Deserialize<float>(reader);

        reader.Read();
        reader.Read();
        var z = serializer.Deserialize<float>(reader);

        reader.Read();
        reader.Read();
        var w = serializer.Deserialize<float>(reader);

        return new Vector4(x, y, z, w);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Vector4 vectorValue = (Vector4)value;

        writer.WriteStartObject();

        writer.WritePropertyName("X");
        writer.WriteValue(vectorValue.X);

        writer.WritePropertyName("Y");
        writer.WriteValue(vectorValue.Y);

        writer.WritePropertyName("Z");
        writer.WriteValue(vectorValue.X);

        writer.WritePropertyName("W");
        writer.WriteValue(vectorValue.Y);

        writer.WriteEndObject();
    }
}

Vector2Converter 完全相同,只是它不包含 Z 和 W 属性的代码,而且名称不同。

反序列化过程将成功通过第一个,但甚至无法进入第二个。

矢量 类 可以在这里找到:https://github.com/opentk/opentk/tree/develop/Source/OpenTK/Math

Tl;dr - 问题出在您的 Vector[X]Converters 上。您阅读了所有属性,但实际上并没有导航到对象的末尾。您需要在 return 您的具体对象的最后一行之前添加一个额外的 reader.Read()

更深层次的解释:

JSON.NET 在编写自定义转换器时对 JsonReader 的状态很挑剔。你需要一直遍历到reader的末尾,不管你是否真的需要剩下的数据(也就是说,你不能return早)。

在此示例中,您读取了所需的值 (W),然后立即 return 编辑了一个新的具体对象,因为您拥有所需的所有数据。但是,JsonReader 仍在检查 属性 节点,因此 JSON.NET 认为仍有数据等待反序列化。这就是为什么你得到

Additional text found in json string after finishing deserializing object

如果您在 JsonConverter 中放置一个断点并在您通过标记前进时观察 reader 对象的状态,您可以自己看到这一点。最后一个,状态是:

...
Path: "LabelColor.W"
TokenType: Float
Value: 1.0
....

如果您将 JsonReader 保持在该状态,您将收到错误消息。但是,如果你最后做一个reader.Read(),那么状态是:

...
Path: "LabelColor"
TokenType: EndObject
Value: null
...

现在JSON.NET很开心!

最简单的读取方法是加载到 JToken 并按名称访问属性,如下所示:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var vec = new Vector4();

        if (token["X"] != null)
            vec.X = (float)token["X"];
        if (token["Y"] != null)
            vec.Y = (float)token["Y"];
        if (token["Z"] != null)
            vec.Z = (float)token["Z"];
        if (token["W"] != null)
            vec.W = (float)token["W"];
        return vec;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Vector4 vectorValue = (Vector4)value;

        writer.WriteStartObject();

        writer.WritePropertyName("X");
        writer.WriteValue(vectorValue.X);

        writer.WritePropertyName("Y");
        writer.WriteValue(vectorValue.Y);

        writer.WritePropertyName("Z");
        writer.WriteValue(vectorValue.Z);

        writer.WritePropertyName("W");
        writer.WriteValue(vectorValue.W);

        writer.WriteEndObject();
    }
}

加载到 JToken 并按名称访问还允许发件人以任何顺序写入 JSON 属性,这是首选,因为 JSON spec states that property name/value pairs are unordered.

此外,请注意我修正了 WriteJson 中的几个错误(代码将 XY 写了两次)和 CanConvert.[=18= 中的一个错误]