在自定义 JsonConverter 的 ReadJson 方法中处理空对象



我有一个Newtonsoft JSON.NET 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)
    {
        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; }
}

当对具有非空PetPerson进行反序列化时,这可以很好地工作。但是,如果Pet为空,那么ReadJson方法在第一行中断,这是一个JsonReaderException:

Newtonsoft.Json.dll中发生类型为"Newtonsoft.Json.JsonReaderException"的异常,但未在用户代码中处理

附加信息:从JsonReader读取JObject时出错。当前JsonReader项不是对象:Null。路径"宠物",第1行,位置11。

我已经查看了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);
    }
}

在写问题时,特别是在写"我尝试了什么"时,我找到了一个可能的解决方案:

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

相关内容

  • 没有找到相关文章

最新更新