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

标签 c# json json.net

我有一个 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 为 null,则 ReadJson 方法会在第一行中断并出现此 JsonReaderException:

An exception of type 'Newtonsoft.Json.JsonReaderException' occurred in Newtonsoft.Json.dll but was not handled in user code

Additional information: Error reading JObject from JsonReader. Current JsonReader item is not an object: Null. Path 'Pet', line 1, position 11.

我检查过 the Custom JsonConverter文档,但它仅仅是关于一个编写转换器。我尝试了以下方法:

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

但后来我得到:

JsonSerializationException: Additional text found in JSON string after finishing deserializing object.

对于属性填充的情况。

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


为了完整起见,这里有一些单元测试可以证明手头的问题:

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

关于c# - 在自定义 JsonConverter 的 ReadJson 方法中处理空对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34185295/

相关文章:

C# 错误还是脑筋急转弯? Cast 仅与 Coalesce (??) 运算符一起使用

c# - C# 中的接口(interface)

android - 如何从 dart/flutter 将 int/integer 值作为 json 发布

c# - 当只读属性与对象引用一起使用时 Json.NET 失败?

c# - 将C#对象序列化为json

c# - 从 Controller Asp.Net MVC 返回动态数组

c# - 使用 CsvHelper 仅将选定的列写入 CSV 文件

java - 使用 AsyncTask 从 JSON 中获取数据

python - 为什么 json 文件会有这样的行为?

c# - Json.NET Windows Store App认证崩溃