I've got a Newtonsoft JSON.NET JsonConverter
to help deserialize a property whose type is an abstract class. The gist of it looks like this:
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(); }
}
Here are the classes it handles:
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; }
}
当反序列化具有非空Pet
的Person
时,这可以很好地工作.但是如果Pet
为空,那么ReadJson
方法在第一行用JsonReaderException
中断:
Newtonsoft.Json.dll中出现‘Newtonsoft.Json.JsonReaderException’类型的异常,但未在用户代码中处理
其他信息:从JsonReader读取JObject时出错.当前JsonReader项目不是对象:Null.路径‘Pet’,第1行,位置11.
我查阅了the Custom JsonConverter份文档,但它只是一个writing转换器.我试过以下方法:
if (reader.Value == null) return null; // this inverts the [Test] results
But then I get:
JsonSerializationException: Additional text found in JSON string after finishing deserializing object.
如果该房产有is人居住.
简而言之,处理这种情况的正确方法是什么?
For completeness, here are some unit tests that demonstrate the issue at hand:
[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);
}
}