JSON.NET:如何根据父(持有者)对象值反序列化接口属性?
我有这样的课程
class Holder { public int ObjType { get; set; } public List Objects { get; set; } } abstract class Base { // ... doesn't matter } class DerivedType1 : Base { // ... doesn't matter } class DerivedType2 : Base { // ... doesn't matter }
使用WebAPI我想要接收对象Holder
并正确反序列化它。 基于ObjType
值,我需要将Objects
属性反序列化为List
( ObjType == 1
)或List
( ObjType == 2
)。
目前我搜索了SO和互联网以获得最佳方法,但我发现的最好的是这个答案https://stackoverflow.com/a/8031283/1038496 。 这个解决方案的问题是,它松散了父对象的上下文,所以我找不到ObjType
的值。 好的,我可以通过为Holder
创建自定义JsonConverter
并记住ObjType
值来解决它,但我仍然害怕这一行
serializer.Populate(jObject.CreateReader(), target);
如下面的评论这个答案所说
在ReadJson方法中创建的新JsonReader不会inheritance任何原始读者的配置值(Culture,DateParseHandling,DateTimeZoneHandling,FloatParseHandling等等)。 在serializer.Populate()中使用新的JsonReader之前,应复制这些值。
这对我来说是个问题并且我自己复制这些值对我来说似乎并不干净(如果我错过了什么怎么办?)
所以问题是: 是否有更好的方法我错过了基于父属性值反序列化抽象对象属性?
你走在正确的轨道上。 您需要为Holder
类实现一个自定义JsonConverter
来处理这种情况,如您所建议的那样。 但是,不用担心,可以以这样的方式编写转换器,即可以使用传递给转换器的原始读取器和序列化器实例,而无需将设置复制到新实例。 这是我写它的方式:
class HolderConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Holder)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); Holder holder = new Holder(); holder.ObjType = (int)jo["ObjType"]; holder.Objects = new List (); foreach (JObject obj in jo["Objects"]) { if (holder.ObjType == 1) holder.Objects.Add(obj.ToObject(serializer)); else holder.Objects.Add(obj.ToObject(serializer)); } return holder; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
这是一个快速演示:
class Program { static void Main(string[] args) { string json = @" [ { ""ObjType"" : 1, ""Objects"" : [ { ""Id"" : 1, ""Foo"" : ""One"" }, { ""Id"" : 2, ""Foo"" : ""Two"" }, ] }, { ""ObjType"" : 2, ""Objects"" : [ { ""Id"" : 3, ""Bar"" : ""Three"" }, { ""Id"" : 4, ""Bar"" : ""Four"" }, ] }, ]"; List list = JsonConvert.DeserializeObject>(json); foreach (Holder holder in list) { if (holder.ObjType == 1) { foreach (DerivedType1 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + " Foo: " + obj.Foo); } } else { foreach (DerivedType2 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + " Bar: " + obj.Bar); } } } } } [JsonConverter(typeof(HolderConverter))] class Holder { public int ObjType { get; set; } public List Objects { get; set; } } abstract class Base { public int Id { get; set; } } class DerivedType1 : Base { public string Foo { get; set; } } class DerivedType2 : Base { public string Bar { get; set; } }
输出:
Id: 1 Foo: One Id: 2 Foo: Two Id: 3 Bar: Three Id: 4 Bar: Four