2017-09-03 90 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的原因。 –