У меня есть 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; }
}
Это отлично работает при десериализации a Person
, у которого есть ненулевой Pet
. Но если значение Pet
равно нулю, то метод ReadJson
разбивается на первую строку с этим a JsonReaderException
:
Исключение типа "Newtonsoft.Json.JsonReaderException" произошло в Newtonsoft.Json.dll, но не было обработано в коде пользователя
Дополнительная информация: Ошибка чтения JObject из JsonReader. Текущий элемент JsonReader не является объектом: Null. Путь 'Pet', строка 1, позиция 11.
Я проверил пользовательскую 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);
}
}