我有一个带有一些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和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
答案 0 :(得分:8)
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很高兴!
答案 1 :(得分:7)
执行读取的最简单方法是加载到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
中的一些错误(代码写了X
和Y
两次)和CanConvert
中的错误。