2017-09-03 72 views
1

不工作时,我有一个类Foo及其作为FooConverter定义如下:定制JsonConverter使用JsonReader代替JsonSerializer

[JsonConverter(typeof(FooConverter))] 
public class Foo 
{ 
    public string Something { get; set; } 
} 

public class FooConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     writer.WriteValue(((Foo)value).Something); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var str = reader.ReadAsString(); 
     if (str == null) 
     { 
      throw new JsonSerializationException(); 
     }  
     // return new Foo {Something = serializer.Deserialize<string>(reader)}; 
     return new Foo {Something = str}; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Foo); 
    } 
} 

序列化工作正常。但是,反序列化时:

var foo = JsonConvert.DeserializeObject<Foo>("\"something\""); 

它抛出JsonSerializationException因为reader.ReadAsString为空。
但我不明白为什么它必须是null ... reader.ReadAsString作品完美地发现,如果我做手工,像这样:

var reader = new JsonTextReader(new StringReader("\"something\"")); 
var str = reader.ReadAsString(); // str is now `something` NOT null 

虽然我可以用serializer.Deserialize<string>(reader)ReadJson修复FooConverter,我仍然想知道为什么reader.ReadAsStringFooConverter.ReadJson失败。

+0

如果你正在寻找一个'JsonConverter'可序列化对象作为字符串原始的,看到'StringIdConverter'从[Json.Net:可以按如下步骤进行修改序列化/反序列化属性的值,不作为对象](https://stackoverflow.com/a/40480742/3744182)。 – dbc

+0

@dbc这很有趣。 'JToken.Load(reader)'正确读取字符串。你知道为什么reader.ReadAsString()不? –

+0

是的,现在添加一个答案。 – dbc

回答

2

您的问题是,根据documentationJsonReader.ReadAsString()

读取下一个来自源的JSON令牌作为字符串。

但是,当调用JsonConverter.ReadJson()时,读者已经位于与被反序列化的对象相对应的第一个JSON令牌。因此,通过调用ReadAsString()你丢弃的价值和尝试读取流中的下一个标记 - 却是没有,所以你抛出一个异常。

此外,在的ReadJson()代码末尾必须定位在最后JSON令牌对应于对象的读取器被转换。所以,在JSON只是一个简单的情况下,读者不应该先进。

确保阅读器始终正确定位ReadJson()的一种简单方法是致电JToken.Load()。这总是让读者定位在已加载的令牌的末尾。之后,您可以检查是否按预期加载了内容。例如,如果JSON有一个对象需要一个字符串,而不是让阅读器错误定位,那么转换器应该抛出一个异常,而不是让阅读器错误定位。

StringIdConverter from Json.Net: Serialize/Deserialize property as a value, not as an object给出了一个例子。

public class FooConverter : JsonConverter 
{ 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var token = JToken.Load(reader); 
     if (!(token is JValue)) 
      throw new JsonSerializationException("Token was not a primitive"); 
     return new Foo { Something = (string)token }; 
    } 
+0

谢谢!这解释了它。 –

0

"\"something\""不是有效的JSON,它只是一个转义字符串。 JSON = JavaScript对象表示法,其中一个空对象定义为{}

与状态的对象仅仅是一个字典结构,其中键具有值。您Foo类型有一个属性Something,这是关键,它需要被分配一个值。因此,尝试一个JSON对象是这样的:

{ Something: "a value" } 

这在C#将被转换这样的:

var foo = JsonConvert.DeserializeObject<Foo>("{\"Something\":\"a value\"}"); 
+0

是的,这是问题所在。我怀疑'JsonReader'特别寻找正确定义的JSON属性。 –

+0

@DanielMay然后为什么JsonReader工作正常,当我手动使用它? (从问题中可以看出) –

+0

@Dvs我无法使用它,因为我需要手动反序列化。这就是我使用JsonConverter的原因。 –