zoukankan      html  css  js  c++  java
  • Newton.Json中JsonConverter的使用

    一、使用场景:

    有两个类都继承了同一个抽象类:

    /// <summary>
    /// 沙盒基类
    /// </summary>
    abstract class SandBoxGanmeBase
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }
    
        /// <summary>
        /// 版本
        /// </summary>
        public string Version { get; set; }
    
        /// <summary>
        /// 可以驾驶
        /// </summary>
        public bool CanDrive { get { return true; } }
    }
    
    /// <summary>
    /// GTA
    /// </summary>
    class GTA5 : SandBoxGanmeBase
    {
        public bool HasHotCoffe { get; set; }
    }
    
    /// <summary>
    /// Cyberpunk2077
    /// </summary>
    class Cyberpunk2077 : SandBoxGanmeBase
    {
        public bool CanModifyDingDing { get { return true; } }
    }

    把信息保存入json:

    string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";
    
    IList<SandBoxGanmeBase> games = new List<SandBoxGanmeBase>();
    
    games.Add(new GTA5()
    {
        Name = "GTA5",
        Version = "1.53",
        HasHotCoffe = true
    });
    
    games.Add(new Cyberpunk2077()
    {
        Name = "Cyberpunk2077",
        Version = "1.06"
    });
    
    string sJson = JsonConvert.SerializeObject(games, Formatting.Indented);
    
    if (!File.Exists(sJsonFile))
        File.Create(sJsonFile).Close();
    
    using (TextWriter chsTw = new StreamWriter(sJsonFile))
    {
        chsTw.WriteLine(sJson);
    chsTw.Flush();
    }

    games.json 内容:

     一般的,使用如下代码读取 games.json:

     string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";
    
     string sJson = string.Empty;
     using (StreamReader sr = new StreamReader(sJsonFile))
         sJson = sr.ReadToEnd();
    
     IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson);

    会 catch ex 报错:

    因为,抽象类在 Newton.Json 反序列化时,无法确定继承抽象类的实例,因此,我们必须要告诉 Newton.Json:你需要使用哪个类来进行反序列化,因此,JsonConverter 应运而生。

    二、自定义 JsonConverter

    class MyJsonConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(SandBoxGanmeBase).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            try
            {
                var jsonObject = JObject.Load(reader);
                object target = null;
                JToken gameName;
                if (jsonObject.TryGetValue("Name", out gameName))
                {
                    switch (gameName.ToString())
                    {
                        case "GTA5":
                            target = new GTA5();
                            break;
                        case "Cyberpunk2077":
                            target = new Cyberpunk2077();
                            break;
                    }
                }
                serializer.Populate(jsonObject.CreateReader(), target);
                return target;
            }
            catch (Exception ex)
            {
                throw new Exception("解析异常:" + ex.Message);
            }
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
    
        }
    }

    修改读取 games.json 代码为:

    string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";
    
    string sJson = string.Empty;
    using (StreamReader sr = new StreamReader(sJsonFile))
        sJson = sr.ReadToEnd();
    
    IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson, new MyJsonConverter());

    反序列化正常:

    三、拓展----用特性方式使用 JsonConverter

    1、反序列化

    SandBoxGanmeBase 增加特性,修改为:

    /// <summary>
    /// 沙盒基类
    /// </summary>
    [JsonConverter(typeof(MyJsonConverter))]
    abstract class SandBoxGanmeBase
    {
        ...
    }

    读取 games.json 方法还原为:

    ...
    
    IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson);

    2、序列化

    仅为 SandBoxGanmeBase 增加了特性,再进行序列化时,序列化的 Json 字符串为空,修改 MyJsonConverter,增加 CanWrite 属性:

    class MyJsonConverter : JsonConverter
    {
        ...

    public
    override bool CanWrite { get { return false; } } ...

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { } }

    这样,在序列化对象时,就使用 Newton.Json 默认的 WriteJson 而不是使用 MyJsonConvert 中重写的 WriteJson。

    这应该是2020年最后一篇博客记录了,2021年,一如既往,不要在小问题上重复犯错!

  • 相关阅读:
    WCF实现上传图片功能
    C#中String.Empty、NULL与""三者的区别
    C#中equal与==的区别
    static 关键字的使用,静态和非静态类的区别
    C#索引器
    C# 接口的隐式与显示实现说明
    Python文件处理
    Python3.X与urllib
    python中if __name__ == '__main__'
    Python中的random模块
  • 原文地址:https://www.cnblogs.com/seanyan/p/14184995.html
Copyright © 2011-2022 走看看