Newtonsoft.Json 处理多态类型的反序列化

Posted 零点blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Newtonsoft.Json 处理多态类型的反序列化相关的知识,希望对你有一定的参考价值。

Newtonsoft.Json的序列化和反序列化很成熟也很好用, 最近在处理多态类型的反序列化中遇到了问题, 反序列化后只能到基类,而得不到也不能转换到子类。从网上查询了一番后,需要写一个创建类型的Converter, 下面我们一步一步来:

1. 首先说明类型的定义, 为了做这个实验,我定义了一个基类和两个子类, 然后我要序列化的对象包含了这个基类的集合。

namespace LexSry
{
    using Newtonsoft.Json;
    using System.Collections.Generic;
    class DemoData
    {
        [JsonProperty("demoId")]
        public int DemoId { get; set; }

        [JsonProperty("demos")]
        public List<DemoBase> Demos { get; set; }
    }

    public class DemoBase
    {
        [JsonProperty("id")]
        public int Id { get; set; }
        [JsonProperty("name")]
        public string Name { get; set; }
        [JsonProperty("type")]
        public string Type { get; set; }
    }

    public class DemoA : DemoBase
    {
        [JsonProperty("color")]
        public string Color { get; set; }

    }

    public class DemoB: DemoBase
    {
        [JsonProperty("size")]
        public double[] Size { get; set; }
    }
}

2. 序列化,反序列化方法。反序列化时使用 JsonConvert.DeserializeObject<T>(string value, param JsonConverter[] converter)。 通过自己定义JsonConverter来实现创建相应的子类。

在本演示中, 我首先创建了抽象类 JsonCreationConverter<T>:JsonConverter ,

其次, 针对于DemoBase的解析, 我创建了 JsonDemoConverter:JsonCreationConverter<DemoBase>

    class JsonParser3
    {
        public static void WriteJson(object t, string file)
        {
            JsonSerializer serializer = new JsonSerializer();
            using (StreamWriter sw = new StreamWriter(file))
            {
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    serializer.Serialize(writer, t);
                }
            }
        }

        public static void ReadJson<T>(string file, out T obj)
        {   
            JsonSerializer serializer = new JsonSerializer();
            using (StreamReader sr = new StreamReader(file))
            {
                obj = JsonConvert.DeserializeObject<T>(sr.ReadToEnd(),new JsonDemoConverter());
            }
        }
    }

    public abstract class JsonCreationConverter<T>:JsonConverter
    {
        protected abstract T Create(Type objectType, JObject jsonObject);
        public override bool CanConvert(Type objectType)
        {
            return typeof(T).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var jsonObject = JObject.Load(reader);
            var target = Create(objectType, jsonObject);
            serializer.Populate(jsonObject.CreateReader(), target);
            return target;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

    public class JsonDemoConverter:JsonCreationConverter<DemoBase>
    {
        protected override DemoBase Create(Type objectType, JObject jsonObject)
        {
            var typeName = jsonObject["type"].ToString();
            switch(typeName)
            {
                case "A":
                    return new DemoA();
                case "B":
                    return new DemoB();
                default: return null;
            }
        }
    }
}

3. 在代码中实现将内存中的对象序列化到test.json中, 然后,从test.json中将数据反序列化到内存对象nData:

            DemoData data = new DemoData()
            {
                DemoId = 1,
                Demos = new List<DemoBase>()
                {
                    new DemoA() {Id=1, Name="demoA", Type="A",Color="red" },
                    new DemoB() {Id=2, Name="", Type="B",Size= new double[]{ 10,10} }
                }
            };

            JsonParser3.WriteJson(data, "test.json");

            DemoData nData = new DemoData();
            JsonParser3.ReadJson<DemoData>("test.json", out nData);

4. test.json中的数据:

{
  "demoId": 1,
  "demos": [
    {
      "color": "red",
      "id": 1,
      "name": "demoA",
      "type": "A"
    },
    {
      "size": [ 10.0, 10.0 ],
      "id": 2,
      "name": "",
      "type": "B"
    }
  ]
}

5. 反序列化后, 内存中得到的对象nData
技术分享

 

以上是关于Newtonsoft.Json 处理多态类型的反序列化的主要内容,如果未能解决你的问题,请参考以下文章

System.Text.Json 中是不是可以进行多态反序列化?

用JavaScript实现字符串的反序输出?

C# dynamic类型序列化和反序列化之Newtonsoft.Json,动态解析远端返回的jSON数据

“Newtonsoft.Json.JsonConvert”类型存在于“Newtonsoft.Json.dll”和“NuGetApi2.dll”中

C# Newtonsoft.Json JsonSerializerSettings 全局序列化设置

无法将类型“newtonsoft.json.linq.jtoken”隐式转换为 newt“newtonsoft.json.linq.jvalue”