Newtonsoft.Json高级用法

Newtonsoft.Json 入门介绍 本人是C#小白,这里摘抄并整理了两位大神的文章: Newtonsoft.Json笔记 -JToken、JObject、JArray详解 Json 基于类 Newtonsoft.Json.Linq.JToken的应用简介 简单介绍如何使用Newtonsoft.Json类库和操作Json对象,这里主要介绍Linq to Json类。 Newtonsoft.Json封装类实现了JToken,直接对JS... 阅读详情

From: http://www.cnblogs.com/yanweidie/p/4605212.html

  手机端应用讲究速度快,体验好。刚好手头上的一个项目服务端接口有性能问题,需要进行优化。在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数据,经过分析一个简单的列表接口每一行数据返回了16个字段,但是手机APP端只用到了其中7个字段,剩余9个字段的数据全部都是多余的,如果接口返回数据为40K大小,也就是说大约20K的数据为无效数据,3G网络下20K下载差不多需要1s,不返回无效数据至少可以节约1s的时间,大大提高用户体验。本篇将为大家介绍Newtonsoft.Json的一些高级用法,可以修改很少的代码解决上述问题。

阅读目录

Newtonsoft.Json介绍

  在做开发的时候,很多数据交换都是以json格式传输的。而使用Json的时候,我们很多时候会涉及到几个序列化对象的使用:DataContractJsonSerializer,JavaScriptSerializer 和 Json.NET即Newtonsoft.Json。大多数人都会选择性能以及通用性较好Json.NET,这个不是微软的类库,但是一个开源的世界级的Json操作类库,从下面的性能对比就可以看到它的其中之一的性能优点。

齐全的API介绍,使用方式简单

 

基本用法

  Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity的。下面分别举例说明序列化和反序列化。

DataTable:

复制代码
            //序列化DataTable
            DataTable dt = new DataTable();
            dt.Columns.Add("Age", Type.GetType("System.Int32"));
            dt.Columns.Add("Name", Type.GetType("System.String"));
            dt.Columns.Add("Sex", Type.GetType("System.String"));
            dt.Columns.Add("IsMarry", Type.GetType("System.Boolean"));
            for (int i = 0; i < 4; i++)
            {
                DataRow dr = dt.NewRow();
                dr["Age"] = i + 1;
                dr["Name"] = "Name" + i;
                dr["Sex"] = i % 2 == 0 ? "男" : "女";
                dr["IsMarry"] = i % 2 > 0 ? true : false;
                dt.Rows.Add(dr);
            }
            Console.WriteLine(JsonConvert.SerializeObject(dt));
复制代码

利用上面字符串进行反序列化

 string json = JsonConvert.SerializeObject(dt);
 dt=JsonConvert.DeserializeObject<DataTable>(json);
 foreach (DataRow dr in dt.Rows)
 {
   Console.WriteLine("{0}\t{1}\t{2}\t{3}\t", dr[0], dr[1], dr[2], dr[3]);
 }

Entity序列化和DataTable一样,就不过多介绍了。

高级用法

    1.忽略某些属性

    2.默认值的处理

    3.空值的处理

    4.支持非公共成员

    5.日期处理

    6.自定义序列化的字段名称

  7.动态决定属性是否序列化

    8.枚举值的自定义格式化问题

  9.自定义类型转换

  10.全局序列化设置

 一.忽略某些属性

  类似本问开头介绍的接口优化,实体中有些属性不需要序列化返回,可以使用该特性。首先介绍Json.Net序列化的模式:OptOut 和 OptIn

OptOut默认值,类中所有公有成员会被序列化,如果不想被序列化,可以用特性JsonIgnore
OptIn默认情况下,所有的成员不会被序列化,类中的成员只有标有特性JsonProperty的才会被序列化,当类的成员很多,但客户端仅仅需要一部分数据时,很有用

 

 

 仅需要姓名属性

复制代码
    [JsonObject(MemberSerialization.OptIn)]
    public class Person
    {
        public int Age { get; set; }

        [JsonProperty]
        public string Name { get; set; }

        public string Sex { get; set; }

        public bool IsMarry { get; set; }

        public DateTime Birthday { get; set; }
    }
复制代码

  不需要是否结婚属性

复制代码
    [JsonObject(MemberSerialization.OptOut)]
    public class Person
    {
        public int Age { get; set; }

        public string Name { get; set; }

        public string Sex { get; set; }

        [JsonIgnore]
        public bool IsMarry { get; set; }

        public DateTime Birthday { get; set; }
    }
复制代码

  通过上面的例子可以看到,要实现不返回某些属性的需求很简单。1.在实体类上加上[JsonObject(MemberSerialization.OptOut)] 2.在不需要返回的属性上加上 [JsonIgnore]说明。

二.默认值处理

    序列化时想忽略默认值属性可以通过JsonSerializerSettings.DefaultValueHandling来确定,该值为枚举值

DefaultValueHandling.Ignore
序列化和反序列化时,忽略默认值
DefaultValueHandling.Include
序列化和反序列化时,包含默认值

 

 

 

 [DefaultValue(10)]
 public int Age { get; set; }
 Person p = new Person { Age = 10, Name = "张三丰", Sex = "男", IsMarry = false, Birthday = new DateTime(1991, 1, 2) };
 JsonSerializerSettings jsetting=new JsonSerializerSettings();
 jsetting.DefaultValueHandling=DefaultValueHandling.Ignore;
 Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

最终结果如下:

 

三.空值的处理

  序列化时需要忽略值为NULL的属性,可以通过JsonSerializerSettings.NullValueHandling来确定,另外通过JsonSerializerSettings设置属性是对序列化过程中所有属性生效的,想单独对某一个属性生效可以使用JsonProperty,下面将分别展示两个方式

  1.JsonSerializerSettings

 Person p = new Person { room=null,Age = 10, Name = "张三丰", Sex = "男", IsMarry = false, Birthday = new DateTime(1991, 1, 2) };
 JsonSerializerSettings jsetting=new JsonSerializerSettings();
 jsetting.NullValueHandling = NullValueHandling.Ignore;
 Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

   

   2.JsonProperty

通过JsonProperty属性设置的方法,可以实现某一属性特别处理的需求,如默认值处理,空值处理,自定义属性名处理,格式化处理。上面空值处理实现

 [JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
 public Room room { get; set; }

 

四.支持非公共成员

  序列化时默认都是处理公共成员,如果需要处理非公共成员,就要在该成员上加特性"JsonProperty"

 [JsonProperty]
 private int Height { get; set; }

 

五.日期处理

  对于Dateime类型日期的格式化就比较麻烦了,系统自带的会格式化成iso日期标准,但是实际使用过程中大多数使用的可能是yyyy-MM-dd 或者yyyy-MM-dd HH:mm:ss两种格式的日期,解决办法是可以将DateTime类型改成string类型自己格式化好,然后在序列化。如果不想修改代码,可以采用下面方案实现。

      Json.Net提供了IsoDateTimeConverter日期转换这个类,可以通过JsnConverter实现相应的日期转换

    [JsonConverter(typeof(IsoDateTimeConverter))]
    public DateTime Birthday { get; set; }

  但是IsoDateTimeConverter日期格式不是我们想要的,我们可以继承该类实现自己的日期

复制代码
    public class ChinaDateTimeConverter : DateTimeConverterBase
    {
        private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" };

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            dtConverter.WriteJson(writer, value, serializer);
        }
    }
复制代码

    自己实现了一个yyyy-MM-dd格式化转换类,可以看到只是初始化IsoDateTimeConverter时给的日期格式为yyyy-MM-dd即可,下面看下效果

[JsonConverter(typeof(ChinaDateTimeConverter))]
public DateTime Birthday { get; set; }

   可以根据自己需求实现不同的转换类

 

六.自定义序列化的字段名称

    实体中定义的属性名可能不是自己想要的名称,但是又不能更改实体定义,这个时候可以自定义序列化字段名称。

     [JsonProperty(PropertyName = "CName")]
     public string Name { get; set; }

 

七.动态决定属性是否序列化

  这个是为了实现@米粒儿提的需求特别增加的,根据某些场景,可能A场景输出A,B,C三个属性,B场景输出E,F属性。虽然实际中不一定存在这种需求,但是json.net依然可以支持该特性。

  继承默认的DefaultContractResolver类,传入需要输出的属性

     重写修改了一下,大多数情况下应该是要排除的字段少于要保留的字段,  为了方便书写这里修改了构造函数加入retain表示props是需要保留的字段还是要排除的字段

复制代码
public class LimitPropsContractResolver : DefaultContractResolver
    {
        string[] props = null;

        bool retain;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="props">传入的属性数组</param>
        /// <param name="retain">true:表示props是需要保留的字段  false:表示props是要排除的字段</param>
        public LimitPropsContractResolver(string[] props, bool retain=true)
        {
            //指定要序列化属性的清单
            this.props = props;

            this.retain = retain;
        }

        protected override IList<JsonProperty> CreateProperties(Type type,

        MemberSerialization memberSerialization)
        {
            IList<JsonProperty> list =
            base.CreateProperties(type, memberSerialization);
            //只保留清单有列出的属性
            return list.Where(p => {
                if (retain)
                {
                    return props.Contains(p.PropertyName);
                }
                else
                {
                    return !props.Contains(p.PropertyName);
                }      
            }).ToList();
        }
    
复制代码
        public int Age { get; set; }

        [JsonIgnore]
        public bool IsMarry { get; set; }

        public string Sex { get; set; }
      JsonSerializerSettings jsetting=new JsonSerializerSettings();
      jsetting.ContractResolver = new LimitPropsContractResolver(new string[] { "Age", "IsMarry" });
      Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

  使用自定义的解析类,只输出"Age", "IsMarry"两个属性,看下最终结果.只输出了Age属性,为什么IsMarry属性没有输出呢,因为标注了JsonIgnore

 

 看到上面的结果想要实现pc端序列化一部分,手机端序列化另一部分就很简单了吧,我们改下代码实现一下

复制代码
  string[] propNames = null;
  if (p.Age > 10)
  {
    propNames = new string[] { "Age", "IsMarry" };
  }
  else
  {
      propNames = new string[] { "Age", "Sex" };
  }
  jsetting.ContractResolver = new LimitPropsContractResolver(propNames);
  Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));
复制代码

 

八.枚举值的自定义格式化问题

  默认情况下对于实体里面的枚举类型系统是格式化成改枚举对应的整型数值,那如果需要格式化成枚举对应的字符怎么处理呢?Newtonsoft.Json也帮我们想到了这点,下面看实例

复制代码
    public enum NotifyType
    {
        /// <summary>
        /// Emil发送
        /// </summary>
        Mail=0,

        /// <summary>
        /// 短信发送
        /// </summary>
        SMS=1
    }

    public class TestEnmu
    {
        /// <summary>
        /// 消息发送类型
        /// </summary>
        public NotifyType Type { get; set; }
    }
    JsonConvert.SerializeObject(new TestEnmu());
复制代码

输出结果:  现在改造一下,输出"Type":"Mail"

复制代码
    public class TestEnmu
    {
        /// <summary>
        /// 消息发送类型
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public NotifyType Type { get; set; }
    }
复制代码

其它的都不变,在Type属性上加上了JsonConverter(typeof(StringEnumConverter))表示将枚举值转换成对应的字符串,而StringEnumConverter是Newtonsoft.Json内置的转换类型,最终输出结果

 

九.自定义类型转换

默认情况下对于实体里面的Boolean系统是格式化成true或者false,对于true转成"是" false转成"否"这种需求改怎么实现了?我们可以自定义类型转换实现该需求,下面看实例

复制代码
public class BoolConvert : JsonConverter
    {
        private string[] arrBString { get; set; }

        public BoolConvert()
        {
            arrBString = "是,否".Split(',');
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="BooleanString">将bool值转换成的字符串值</param>
        public BoolConvert(string BooleanString)
        {
            if (string.IsNullOrEmpty(BooleanString))
            {
                throw new ArgumentNullException();
            }
            arrBString = BooleanString.Split(',');
            if (arrBString.Length != 2)
            {
                throw new ArgumentException("BooleanString格式不符合规定");
            }
        }


        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            bool isNullable = IsNullableType(objectType);
            Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;

            if (reader.TokenType == JsonToken.Null)
            {
                if (!IsNullableType(objectType))
                {
                    throw new Exception(string.Format("不能转换null value to {0}.", objectType));
                }

                return null;
            }

            try
            {
                if (reader.TokenType == JsonToken.String)
                {
                    string boolText = reader.Value.ToString();
                    if (boolText.Equals(arrBString[0], StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    else if (boolText.Equals(arrBString[1], StringComparison.OrdinalIgnoreCase))
                    {
                        return false;
                    }
                }

                if (reader.TokenType == JsonToken.Integer)
                {
                    //数值
                    return Convert.ToInt32(reader.Value) == 1;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error converting value {0} to type '{1}'", reader.Value, objectType));
            }
            throw new Exception(string.Format("Unexpected token {0} when parsing enum", reader.TokenType));
        }

        /// <summary>
        /// 判断是否为Bool类型
        /// </summary>
        /// <param name="objectType">类型</param>
        /// <returns>为bool类型则可以进行转换</returns>
        public override bool CanConvert(Type objectType)
        {
            return true;
        }


        public bool IsNullableType(Type t)
        {
            if (t == null)
            {
                throw new ArgumentNullException("t");
            }
            return (t.BaseType.FullName=="System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }

            bool bValue = (bool)value;

            if (bValue)
            {
                writer.WriteValue(arrBString[0]);
            }
            else
            {
                writer.WriteValue(arrBString[1]);
            }
        }
    }
复制代码

 自定义了BoolConvert类型,继承自JsonConverter。构造函数参数BooleanString可以让我们自定义将true false转换成相应字符串。下面看实体里面怎么使用这个自定义转换类型

    public class Person
    {
        [JsonConverter(typeof(BoolConvert))]
        public bool IsMarry { get; set; }
    }

‘

相应的有什么个性化的转换需求,都可以使用自定义转换类型的方式实现。

 

十.全局序列化设置

文章开头提出了Null值字段怎么不返回的问题,相应的在高级用法也给出了相应的解决方案使用jsetting.NullValueHandling = NullValueHandling.Ignore; 来设置不返回空值。这样有个麻烦的地方,每个不想返回空值的序列化都需设置一下。可以对序列化设置一些默认值方式么?下面将解答

复制代码
  Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
   JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
   {
    //日期类型默认格式化处理
     setting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
      setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";

    //空值处理
      setting.NullValueHandling = NullValueHandling.Ignore;

      //高级用法九中的Bool类型转换 设置
      setting.Converters.Add(new BoolConvert("是,否"));

      return setting;
   });
复制代码

 

这样设置以后,以后使用序列化的地方就不需要单独设置了,个人最喜欢设置的是空值处理这一块。

总结

  Newtonsoft.Json序列化库替我们想了很多特性,也实现了很多特性,除了上面介绍的几种高级用法外,还有其它的特殊用法,可以去官网进行学习。当然这里我目前最喜欢的特性就是那个忽略部分属性序列化的功能,很小的代码改动实现了接口的优化,提升了用户体验。


Unity中Newtonsoft.Json的使用(一) 在Unity中下载Newtonsoft.Json,并进行序列化和反序列化 阅读详情

相关推荐

C# Newtonsoft.Json库使用详解

可以通过实现来自定义序列化和反序列化逻辑。set;set;get;set;get;set;// 创建一个Person对象 Person person = new Person {// 使用自定义的PersonConverter进行序列化 string json = JsonConvert . SerializeObject(person , new PersonConverter());// 输出JSON字符串 Console . WriteLine(json);

记录点滴 1822

C# Newtonsoft.Json用法

安装Newtonsoft.Json,在NuGet里直接搜索Newtonsoft.Json下面介绍基本的几个使用方法。

熊思雨的博客 4万+

Qt Design Studio 入门指南:从零开始打造炫酷UI(详细+实用+轻松上手)

本文是Qt Design Studio的详细入门指南,旨在帮助UI设计新手从零开始轻松打造炫酷界面。文章系统介绍了软件的核心概念、安装步骤、主界面解析,并通过创建一个完整的登录界面实例,手把手教学如何拖拽组件、设置属性、添加交互状态与动画。同时,分享了创建自定义组件、管理资源以及提升效率的实用技巧与常见问题解决方案,让读者能够快速上手并应用于实际项目开发。

devops8pract的博客 588

Newtonsoft.Json

Newtonsoft.Json是一款高性能Json序列化和解析工具,开源免费!它使得配置文件的保存和读取变得简单,提供对类属性和字段的序列化控制,以及在序列化过程中或完成后执行相应的方法。

weixin_42253874的博客 6135

ROS 2 Jazzy与Gazebo Harmonic仿真实战:从零搭建机器人仿真环境与高级应用

本文详细介绍了如何使用ROS 2 Jazzy和Gazebo Harmonic从零搭建机器人仿真环境,涵盖环境配置、传感器集成、多机器人协同和GPU加速优化等高级应用。通过实战案例和性能调优技巧,帮助开发者高效构建可靠的机器人仿真系统,提升开发效率。

h9j8k7l6m5n的博客 1217

ADS高级技巧:用DAC控件实现多变量参数扫描(以S参数和阻抗匹配为例)

本文深入解析了ADS软件中DAC控件的高级应用,指导用户如何利用其实现多变量参数扫描。通过构建支持多变量的MDF文件,并将其与原理图变量动态映射,可以高效完成如S参数和阻抗匹配等复杂场景的联合仿真与可视化分析,显著提升射频电路设计的效率和深度。

3a9bq4r8t2y的博客 253

Newtonsoft.Json的高级用法

Newtonsoft.Json的高级用法

伊人回眸泪倾城的博客 696

YOLOv4目标检测算法——通俗易懂的解析

YOLOv4目标检测算法——通俗易懂的解析

chase 7135

java newtonsoft.json_C# Newtonsoft.Json 高级用法

最近在做接口开发,对方团队开发了一个Web API 的接口,传输数据的格式是 JSON。当时看到这个东西,感觉很简单,也没想什么,没用多久就完成了我的功能,我完成的功能很简单,就是获取数据,然后把数据列表进行 JSON 序列化,然后再以 POST 方式调用对方 Web Api 的接口,将 JSON 的数据一起传递过去,我想的很简单,直接调用并返回结果就完成了。最后对方接口返回错误,提示从 传递过去...

weixin_35659266的博客 407

Dify智能体开发:大语言模型(LLM)问题分类

通过定义分类描述,问题分类器能够根据用户输入,使用 LLM 推理与之相匹配的分类并输出分类结果,向下游节点提供更加精确的信息。

王国平的博客 2249

MAVLink协议详解

MAVLink是为微型飞行器MAV(Micro Air Vehicle)设计的(LGPL)开源的通讯协议。是无人飞行器和地面站(Ground Control Station ,GCS)之间,以及无人飞行器之间通讯常用的协议。APM、PIXHAWK飞控,Mission Planner、QGroundControl地面站均使用了MAVLink协议进行通讯。 MAVLink源码下载地址(现已更新至v2.0):https://github.com/mavlink/qgroundcontrol   用户手册:ht

程序猿老樊的博客 7704

163MusicLyrics JSON处理:Newtonsoft.Json高级用法

在音乐歌词获取工具163MusicLyrics中,JSON处理是核心功能之一。项目深度集成了Newtonsoft.Json库,实现了从API响应解析到数据转换的全链路JSON处理能力。本文将深入剖析项目中Newtonsoft.Json的高级用法,帮助开发者掌握高效JSON处理技巧。 ## 项目JSON处理架构概览 163MusicLyrics采用分层JSON处理架构,通过统一的工具类和特定场景...

gitblog_00176的博客 814

(十五)CX20106A 中超声波测量的应用

(十五)CX20106A 中超声波测量的应用

m0_52555663的博客 4511
上一篇: web/html5调用摄像头实现二维码扫描
双鱼达摩
博客等级 码龄18年 8粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值