2015-12-09 47 views
10

我有一个Newtonsoft JSON.NET JsonConverter来帮助反序列化类型为抽象类的属性。它的要点如下:在自定义JsonConverter的ReadJson方法中处理空对象

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(); } 
} 

下面是它处理的类:

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; } 
} 

这反序列化Person具有非空Pet时工作正常。但是,如果Pet为null,则与此第一行ReadJson方法分解的JsonReaderException

类型的异常“Newtonsoft.Json.JsonReaderException”发生在Newtonsoft.Json.dll但没有处理用户代码

附加信息:从JsonReader读取JObject时出错。当前的JsonReader项目不是对象:空。路径“宠物”,1号线,位置11

我检查the Custom JsonConverter文件,但它仅仅是关于转换器。我已经试过如下:

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

但后来我得到:

JsonSerializationException:在JSON字符串中发现整理反序列化对象之后附加文本。

对于情况下,当财产填充。

总之,处理这种情况的正确方法是什么?


为了完整起见,这里有一些单元测试,在手展示问题:

[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

和/或你可以加载JSON作为'JToken'和检查' token.Type == JTokenType.Null'。虽然实际上你的解决方案似乎最好 – dbc

+1

在我的情况下,'reader'在返回null时没有正确的状态。因此,我想出了答案的解决方案和[dbc]的建议的组合:'if(reader.TokenType == JsonToken.Null){JToken.Load(reader);返回null; }'。 – JanDotNet

相关问题