2017-09-03 3 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); 
    } 
} 

シリアライズ正常に動作します。しかし、デシリアライズするとき:それはJsonSerializationExceptionのでreader.ReadAsStringがnullスロー

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


しかし、それはnullなければならない理由を私は理解していない、私はそうのように手動でそれをやっている場合... reader.ReadAsString作品は完全に見つける:

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

私はReadJsonserializer.Deserialize<string>(reader)を使用してFooConverterを修正することができますが、私はまだreader.ReadAsStringFooConverter.ReadJsonで失敗する理由を理解したい。

+0

をあなたは原始的な文字列としてオブジェクトをシリアル化することができます 'JsonConverter'を探している場合は、[Json.Netから' StringIdConverter'を参照してください。シリアライズ/値としてプロパティをデシリアライズ、オブジェクトとしてではありません](https://stackoverflow.com/a/40480742/3744182)。 – dbc

+0

@dbcそれは面白いです。 'JToken.Load(reader)'は正しく文字列を読み込みます。あなたはreader.ReadAsString()がなぜそうでないのか知っていますか? –

+0

はい、今すぐ回答を追加してください。 – dbc

答えて

2

あなたの問題はJsonReader.ReadAsString()documentationによると、ということである:読み込み

次へソースからのJSONトークンを文字列として返します。

ただし、JsonConverter.ReadJson()が呼び出されると、リーダーはすでにデシリアライズされているオブジェクトに対応する最初のJSONトークンに配置されています。したがって、ReadAsString()を呼び出すと、その値を破棄してストリームの次のトークンを読み込もうとしますが、何もないので例外がスローされます。

さらに、ReadJson()の最後に、コードは変換されるオブジェクトに対応する最後のJSONトークンにリーダーを配置する必要があります。したがって、JSONが単なるプリミティブである場合、読者はまったく前進するべきではありません。

ReadJson()によってリーダーが常に正しく配置されることを保証する簡単な方法は、JToken.Load()を呼び出すことです。これにより、読み込まれたトークンの最後にリーダーが常に置かれます。その後、ロードされたものが期待どおりであったかどうかを確認することができます。たとえば、JSONに文字列が必要なオブジェクトがある場合、リーダーの位置を間違えたままにするのではなく、リーダーは正しく配置されていないまま例外をスローする必要があります。

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 Object Notation。空のオブジェクトは{}と定義されています。

状態を持つオブジェクトは、キーが値を持つ単なる辞書構造です。 Fooタイプは、キーであるプロパティーSomethingを持っており、値を割り当てる必要があります。したがって、このようなJSONオブジェクトを試してください:

C#で次のように変換されるだろう
{ Something: "a value" } 

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

これは問題です。私は 'JsonReader'が特に正しく定義されたJSONプロパティーを探すと思う。 –

+0

@DanielMayそれで、JsonReaderを手動で使用するとJsonReaderが正常に動作するのはなぜですか? (質問から分かるように) –

+0

@Dvs手動でデシリアライズする必要があるので、私はそれを使用できません。だからこそ私はJsonConverterを使いました。 –

関連する問題