我有这样的课程
class Holder {
public int ObjType { get; set; }
public List<Base> Objects { get; set; }
}
abstract class Base {
// ... doesn't matter
}
class DerivedType1 : Base {
// ... doesn't matter
}
class DerivedType2 : Base {
// ... doesn't matter
}
使用WebAPI我希望收到对象Holder
并正确反序列化它。根据{{1}}值,我需要将ObjType
属性反序列化为Objects
(List<DerivedType1>
)或ObjType == 1
(List<DerivedType2>
)。
目前我搜索了SO和互联网以获得最佳方法,但我发现的最好的答案是https://stackoverflow.com/a/8031283/1038496。这个解决方案的问题是,它松散了父对象的上下文,所以我找不到ObjType == 2
的值。好的,我可以通过为ObjType
创建自定义JsonConverter
并记住Holder
值来解决这个问题,但我仍然不喜欢这条线
ObjType
如下面的评论所说
在ReadJson方法中创建的新JsonReader不会继承任何原始读者的配置值(Culture,DateParseHandling,DateTimeZoneHandling,FloatParseHandling等等)。在serializer.Populate()中使用新的JsonReader之前,应复制这些值。
这对我来说是个问题并且我自己复制这些值对我来说似乎并不干净(如果我错过了什么呢?)
所以问题是:有没有更好的方法我错过了根据父属性值反序列化抽象对象属性?
答案 0 :(得分:44)
你走在正确的轨道上。您需要为JsonConverter
类实现自定义Holder
来处理这种情况,如您所建议的那样。但是,不用担心,可以以这样的方式编写转换器,即可以使用传递给转换器的原始读取器和序列化器实例,而无需将设置复制到新实例。我就是这样写的:
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<Base>();
foreach (JObject obj in jo["Objects"])
{
if (holder.ObjType == 1)
holder.Objects.Add(obj.ToObject<DerivedType1>(serializer));
else
holder.Objects.Add(obj.ToObject<DerivedType2>(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<Holder> list = JsonConvert.DeserializeObject<List<Holder>>(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<Base> 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