C# json.net错误:意外的令牌反序列化对象
我有一个包含一些json的文件,它是由json.net生成的:C# json.net错误:意外的令牌反序列化对象,c#,json,json.net,C#,Json,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":
[
{
"$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的问题吗?我通过验证器检查了一下,它说没问题
它在“中心”后的空格上出错:如果我更改中心和LabelColor属性的顺序,则它在“LabelColor”后会以相同的方式出错:
以下是类型的转储:
LabelColor是一个OpenTK矢量4,Center是一个OpenTK矢量2,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;
}
这是矢量4转换器:
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();
}
}
public类Vector4Converter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(Vector2);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
reader.Read();
reader.Read();
var x=序列化程序。反序列化(读取器);
reader.Read();
reader.Read();
var y=序列化程序。反序列化(读取器);
reader.Read();
reader.Read();
var z=序列化程序。反序列化(读取器);
reader.Read();
reader.Read();
var w=序列化程序。反序列化(读取器);
返回新矢量4(x,y,z,w);
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
向量4向量值=(向量4)值;
writer.WriteStartObject();
writer.WritePropertyName(“X”);
WriteValue(vectorValue.X);
writer.WritePropertyName(“Y”);
WriteValue(vectorValue.Y);
writer.WritePropertyName(“Z”);
WriteValue(vectorValue.X);
writer.WritePropertyName(“W”);
WriteValue(vectorValue.Y);
writer.WriteEndObject();
}
}
Vector2Converter完全相同,只是它不包含Z和W属性的代码,并且名称不同
反序列化过程将成功完成第一个过程,但甚至不会进入第二个过程
向量类可以在这里找到:Tl;dr-问题出在您的
向量[X]转换器中。您读取了所有属性,但实际上并没有导航到对象的末尾。在返回具体对象的最后一行之前,需要一个额外的reader.Read()
更深层次的解释:
在编写自定义转换器时,JSON.NET对JsonReader
的状态很挑剔。您需要一直遍历到读卡器的末尾,而不管您是否真正需要剩余的数据(换句话说,您不能提前返回)
在本例中,您读取所需的值(W),然后立即返回一个新的具体对象,因为您拥有所需的所有数据。但是,JsonReader
仍在检查属性节点,因此JSON.NET认为仍有数据等待反序列化。这就是为什么你会
完成反序列化对象后,在json字符串中找到其他文本
如果在JsonConverter
中放置断点,并在标记中前进时观察读取器
对象的状态,您可以自己看到这一点。关于最后一个问题,国家是:
...
Path: "LabelColor.W"
TokenType: Float
Value: 1.0
....
...
Path: "LabelColor"
TokenType: EndObject
Value: null
...
如果将JsonReader
保持在该状态,您将得到一个错误。但是,如果执行最后一个reader.Read()
,则状态为:
...
Path: "LabelColor.W"
TokenType: Float
Value: 1.0
....
...
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属性,这是首选的,因为
另外,请注意,我修复了WriteJson
中的几个错误(代码写了X
和Y
两次)在CanConvert
中有一个错误,您是否也可以发布C#types?@UfukHacıoğullarıI已经发布了它们。@DanielA.White错误消息如下:Newtonsoft.Json.Json序列化异常类型的未处理异常发生在Newtonsoft.Json.dll中其他信息:反序列化对象时出现意外令牌:PropertyName。路径“[0]。居中”,第11行,位置14。“中心”后面的空格是什么:为什么你甚至需要一个转换器?十、 Y、Z和W是公共的、可写的字段,因此它们可以开箱即用地正确序列化。@dbc因为opentk中的vector*结构有相当多的字段,而不仅仅是X、Y、Z和W,它们会导致递归引用(例如public Vector2 Verticallright)。另外,只要有x、y、z和w,json的方式就更具可读性。由于这种奇怪之处,我建议使用基于JToken的阅读器,如dbc posted。感谢您对这个问题的解释。我实际上已经使用了dbc的答案,所以我会将其标记为已接受。此外,它应该鼓励人们正确地创建这些。JToken的解决方案比我拥有的要优雅得多,当然更优雅。希望我的解释能帮助其他试图弄明白JSON.NET为何会呕吐的人。干杯这个答案帮助我识别了我的JsonConverter
中的一个问题。我的while循环停止条件是while(reader.Read())
,这是不够的,因为我还有其他没有反序列化的对象。我必须更改while循环以检查reader.TokenType
。在我的例子中,我正在检查JsonToken.EndArray
。