2015-12-09 39 views
10

私はNewtonsoft JSON.NET JsonConverterを持っています。タイプが抽象クラスであるプロパティを逆シリアル化するのに役立ちます。その要旨は次のようになります。null以外Petを持ってPersonをデシリアライズするときこれが正常に動作しますカスタムJsonConverterのReadJsonメソッドでnullオブジェクトを扱う

public abstract class Animal 
{ } 

public class Cat : Animal 
{ 
    public int Lives { get; set; } 
} 

public class Parrot : Animal 
{ 
    public string StopPhrase { get; set; } 
} 

public class Person 
{ 
    [JsonConverter(typeof(PetConverter))] 
    public Animal Pet { get; set; } 
} 

:ここ

public class PetConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Animal); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject jsonObject = JObject.Load(reader); 

     if (jsonObject["Lives"] != null) return jsonObject.ToObject<Cat>(serializer); 
     if (jsonObject["StopPhrase"] != null) return jsonObject.ToObject<Parrot>(serializer); 

     return null; 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { throw new NotImplementedException(); } 
} 

それが扱うクラスです。しかしPetがnullの場合、このとの最初の行にReadJson法の改JsonReaderException:種類の例外「Newtonsoft.Json.JsonReaderException」はNewtonsoft.Json.dllで発生したが、中に処理されなかった

ユーザーコード

追加情報:JsonReaderからJObjectを読み取る際のエラー。現在のJsonReaderアイテムはオブジェクトではありません:Null。パス「ペット」、行1、位置11

私はthe Custom JsonConverterドキュメントをチェックしましたが、それは書き込みコンバータについて過ぎません。

if (reader.Value == null) return null; // this inverts the [Test] results 

をしかし、私は得る:私は次のことを試してみた

JsonSerializationException:デシリアライズオブジェクトを終えた後、JSON文字列で見つかった追加のテキストを。

のプロパティがの場合です。

要するに、この状況を処理する適切な方法は何ですか?特に「私が試し持っているものを」少し、私は1つの可能性を見つけるの書き込み中に、質問を書きながら

[TestFixture] 
public class JsonConverterTests 
{ 
    [Test] 
    public void Cat_survives_serialization_roundtrip() 
    { 
     var person = new Person { Pet = new Cat { Lives = 9 } }; 
     var serialized = JsonConvert.SerializeObject(person); 
     var deserialized = JsonConvert.DeserializeObject<Person>(serialized); 
     Assert.That(deserialized.Pet, Is.InstanceOf<Cat>()); 
     Assert.That((deserialized.Pet as Cat).Lives, Is.EqualTo(9)); 
    } 

    [Test] 
    public void Parrot_survives_serialization_roundtrip() 
    { 
     var person = new Person { Pet = new Parrot { StopPhrase = "Lorrie!" } }; 
     var serialized = JsonConvert.SerializeObject(person); 
     var deserialized = JsonConvert.DeserializeObject<Person>(serialized); 
     Assert.That(deserialized.Pet, Is.InstanceOf<Parrot>()); 
     Assert.That((deserialized.Pet as Parrot).StopPhrase, Is.EqualTo("Lorrie!")); 
    } 

    [Test] 
    public void Null_property_does_not_break_converter() 
    { 
     var person = new Person { Pet = null }; 
     var serialized = JsonConvert.SerializeObject(person); 
     var deserialized = JsonConvert.DeserializeObject<Person>(serialized); 
     Assert.That(deserialized.Pet, Is.Null); 
    } 
} 

答えて

18


は完全を期すために、ここに手で問題を実証し、いくつかのユニットテストです解決策:

if (reader.TokenType == JsonToken.Null) return null; 

私は二つの理由のためにこれを掲示しています:

  1. もしそれが十分であれば、同じ質問をしている他の人に役立つかもしれません。
  2. 私は、他の人の答えからより良い、競合する解決策を学ぶかもしれません。

FWIWは、ここでのフルJsonConverterは、タイプ、抽象クラスである財産の非常に基本的な取り扱いのデシリアライズのためです:

public class PetConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Animal); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) return null; 

     JObject jsonObject = JObject.Load(reader); 

     if (jsonObject["Lives"] != null) return jsonObject.ToObject<Cat>(serializer); 
     if (jsonObject["StopPhrase"] != null) return jsonObject.ToObject<Parrot>(serializer); 

     return null; 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+1

および/またはあなたが 'JToken'としてあなたのJSONをロードし、'のためにチェックすることができtoken.Type == JTokenType.Null'です。実際には、あなたのソリューションは最高のようです。 – dbc

+1

私の場合、nullを返すとき、 'reader'は正しい状態を持っていませんでした。したがって、私は答えのソリューションと[dbc]の提案の組み合わせを思いついた。if(reader.TokenType == JsonToken.Null){JToken.Load(reader); nullを返す。 } '。 – JanDotNet

関連する問題