JSON.NET: How to deserialize interface property based on parent (holder) object value?

前端 未结 1 1500
抹茶落季
抹茶落季 2020-12-23 11:58

I have such classes

class Holder {
    public int ObjType { get; set; }
    public List Objects { get; set; }
}

abstract class Base {
    // ...          


        
相关标签:
1条回答
  • 2020-12-23 12:47

    You are on the right track. You do need to implement a custom JsonConverter for your Holder class to handle this situation, as you suggested. But, don't worry, it is possible to write the converter in such a way that you can use the original reader and serializer instances passed to the converter, without ever needing to copy the settings over to new instances. Here is how I would write it:

    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();
        }
    }
    

    Here is a quick demo:

    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; }
    }
    

    Output:

    Id: 1  Foo: One
    Id: 2  Foo: Two
    Id: 3  Bar: Three
    Id: 4  Bar: Four
    
    0 讨论(0)
提交回复
热议问题