json.net错误:意外的令牌反序列化对象



我有一个文件,里面有一些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"之后的空格中出错:如果我更改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属性的代码,并且名称不同。

反序列化过程将成功地完成第一个过程,但甚至不会进入第二个过程。

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

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

更深层次的解释:

在编写自定义转换器时,JSON.NET对JsonReader的状态非常挑剔。您需要一直遍历到读取器的末尾,而不管您是否真的需要剩余的数据(换句话说,您不能提前返回(。

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

完成反序列化对象后,在json字符串中发现其他文本

如果在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规范规定属性名称/值对是无序的。

此外,请注意,我修复了WriteJson中的几个错误(代码写了两次XY(和CanConvert中的一个错误。

相关内容

  • 没有找到相关文章

最新更新