Ответ 1
Вы на правильном пути. Вам необходимо реализовать пользовательский 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