zoukankan      html  css  js  c++  java
  • Newtonsoft.Json 的高级用法

    Ø  简介

    接着前一篇http://www.cnblogs.com/abeam/p/8295765.html,继续研究 Newtonsoft.Json 的一些高级用法。主要包括:

    1.   JSON 格式化

    2.   忽略指定成员

    3.   忽略默认值成员

    4.   忽略空值(null)成员

    5.   驼峰命名序列化成员

    6.   日期类型格式化

    7.   解决序列化对象循环引用

    8.   使用 JsonConverter 自定义成员转换

    9.   使用 DefaultContractResolver(契约分解器)指定序列化成员

    10.  使用 JsonSerializer 对象序列化与反序列化

     

    Ø  首先,准备数据

    Goods[] goods = new Goods[]

    {

        new Goods()

        {

            GoodsId = 1,

            GoodsName = "联想ThinkPad无线鼠标",

            //Price = 125.00m,

            //IsQuota = true,

            Attributes = new Goods.Attribute[]

            {

                new Goods.Attribute() { Name = "品牌", Value = "Lenovo/联想" },

                new Goods.Attribute() { Name = "颜色", Value = "黑色" }

            },

            Status = Status.Online

        }

    };

     

    1.   JSON 格式化(可以采用以下2种方式)

    1)   简单格式化(推荐)

    string jsonStr1_1_1 = JsonConvert.SerializeObject(goods, Newtonsoft.Json.Formatting.Indented);

    结果:

    [

      {

        "GoodsName": "联想ThinkPad无线鼠标",

        "IsQuota": true,

        "Status": "Online"

      }

    ]

     

    2)   使用 Newtonsoft.Json.JsonTextWriter 格式化

    JsonSerializer serializer1 = new JsonSerializer();

    using (StringWriter textWriter = new StringWriter())

    {

        using (JsonTextWriter jsonWriter = new JsonTextWriter(textWriter))

        {

            jsonWriter.Formatting = Newtonsoft.Json.Formatting.Indented;    //默认为Formatting.None

            jsonWriter.Indentation = 4;     //缩进字符数,默认为2

            jsonWriter.IndentChar = ' ';    //缩进字符,默认为' '

            serializer1.Serialize(jsonWriter, goods);

        }

        string jsonStr1_2_1 = textWriter.ToString();

    }

    结果:

    [

        {

            "GoodsName": "联想ThinkPad无线鼠标",

            "IsQuota": true,

            "Status": "Online"

        }

    ]

     

    2.   忽略指定成员

    忽略指定序列化成员使用 JsonIgnore 特性,例如(修改 Goods):

    /// <summary>

    /// 商品名称

    /// </summary>

    [JsonIgnore]

    public string GoodsName { get; set; }

     

    1)   序列化

    string jsonStr2_1 = JsonConvert.SerializeObject(goods);

    结果:[{"IsQuota":true,"Status":"Online"}]

     

    2)   反序列化

    string jsonStr2_2 = "[{"GoodsName": "联想ThinkPad无线鼠标","IsQuota":true,"Status":"Online"}]";

    Goods[] jsonObj2_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr2_2);

    结果:

    clip_image001[1]

     

    3.   忽略默认值成员(忽略 GoodsId Price 这两个默认值)

    可以采用两种方式实现:

    1. 使用 JsonSerializerSettings 对象;

    2. 成员标记 JsonProperty 特性并指定 DefaultValueHandling 属性。

    下面演示第一种实现方式:

    1)   加入 DefaultValue 特性(修改 goods

    /// <summary>

    /// 价格

    /// </summary>

    [System.ComponentModel.DefaultValue(125.00)]

    public decimal Price { get; set; }

     

    2)   创建 JsonSerializerSettings 对象

    goods[0].GoodsId = 0;   //int 类型的本身默认值(0

    goods[0].Price = 125;   //加了 System.ComponentModel.DefaultValue 特性的默认值(125

    var settings1 = new JsonSerializerSettings();

    settings1.DefaultValueHandling = DefaultValueHandling.Ignore;   //默认为Include

     

    3)   序列化

    string jsonStr3_1 = JsonConvert.SerializeObject(goods, settings1);

    结果:[{"GoodsName":"联想ThinkPad无线鼠标","IsQuota":true,"Status":"Online"}]

     

    4)   反序列化

    string jsonStr3_2 = "[{"GoodsId":0,"GoodsName":"联想ThinkPad无线鼠标","Price":125,"IsQuota":true,"Status":"Online"}]";

    Goods[] jsonObj3_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr3_2, settings1);

    结果:

    clip_image002[1]

     

    4.   忽略空值(null)成员

    可以采用两种方式实现:

    1. 使用 JsonSerializerSettings 对象;

    2. 成员标记 JsonProperty 特性并指定 NullValueHandling 属性。

    下面演示第一种实现方式:

    goods[0].GoodsName = null;

    var settings2 = new JsonSerializerSettings();

    settings2.NullValueHandling = NullValueHandling.Ignore; //默认为Include

    1)   序列化

    string jsonStr4_1 = JsonConvert.SerializeObject(goods, settings2);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":true,"Status":"Online"}]

     

    5.   驼峰命名序列化成员

    var settings3 = new JsonSerializerSettings();

    settings3.ContractResolver = new CamelCasePropertyNamesContractResolver();

    1)   序列化

    string jsonStr5_1 = JsonConvert.SerializeObject(goods, settings3);

    结果:[{"goodsId":0,"price":125.0,"isQuota":true,"status":"Online"}]

     

    6.   日期类型格式化

    日期类型默认情况下,会序列化为一个带有“T”字符的日期字符串,比如:2018-04-24T17:58:26.0096087+08:00可以采用两种方式对日期类型格式化,例如(修改 Goods):

    /// <summary>

    /// 创建时间

    /// </summary>

    public DateTime CreateTime { get;set;}

    goods[0].CreateTime = DateTime.Now; //2018/4/24 17:58:26

     

    1)   默认序列化

    string jsonStr6_1 = JsonConvert.SerializeObject(goods);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":true,"Status":"Online","CreateTime":"2018-04-24T17:58:26.0096087+08:00"}]

     

    2)   使用 JsonSerializerSettings 对象格式化

    var settings4 = new JsonSerializerSettings();

    settings4.DateFormatString = "yyy-MM-dd";   //默认为:yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK

    string jsonStr6_2 = JsonConvert.SerializeObject(goods, settings4);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":true,"Status":"Online","CreateTime":"2018-04-24"}]

     

    3)   使用 IsoDateTimeConverter 对象格式化

    var dateTimeConverter1 = new IsoDateTimeConverter();

    dateTimeConverter1.DateTimeFormat = "yyy-MM-dd HH:mm:ss fff";   //默认为""

    string jsonStr6_3 = JsonConvert.SerializeObject(goods, dateTimeConverter1);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":true,"Status":"Online","CreateTime":"2018-04-24 17:58:26 009"}]

     

    4)   也可以在日期类型成员指定 JsonConverter 特性,例如:

    /// <summary>

    /// 创建时间

    /// </summary>

    [JsonConverter(typeof(Newtonsoft.Json.Converters.IsoDateTimeConverter))]

    public DateTime CreateTime { get;set;}

     

    7.   解决序列化对象循环引用

    处理循环引用使用 JsonSerializerSettings 对象,并设置 ReferenceLoopHandling 属性,该属性是一个枚举类型,解释如下:

    Error

    默认值,发生循环引用时将抛出序列化异常:Newtonsoft.Json.JsonSerializationException

    Ignore

    忽略循环引用的成员

    Serialize

    继续序列化,不管是否存在循环引用,指定该值将抛出溢出异常:System.StackOverflowException(感觉这个值没什么用?)

    下面模拟循环引用场景(修改 Goods):

    /// <summary>

    /// 订单明细

    /// </summary>

    public OrdersDetail OrdersDetail { get; set; }

    /// <summary>

    /// 订单明细

    /// </summary>

    public class OrdersDetail

    {

        /// <summary>

        /// 商品集合

        /// </summary>

        public Goods[] Goods { get; set; }

    }

    OrdersDetail od = new OrdersDetail() { Goods = goods };

    goods[0].OrdersDetail = od;

     

    1)   序列化

    string jsonStr7_1 = JsonConvert.SerializeObject(goods); //将抛出 JsonSerializationException 异常

     

    2)   忽略循环引用

    var settings5 = new JsonSerializerSettings();

    settings5.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    string jsonStr7_2 = JsonConvert.SerializeObject(goods, settings5);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":true,"Status":"Online","CreateTime":"2018-04-25T09:57:52.8628936+08:00","OrdersDetail":{}}]

     

    8.   使用 JsonConverter 自定义成员转换

    自定义成员转换使用 JsonConverter 类,该类是一个抽象类,实现 WriteJson()ReadJson() 方法完成自定义序列化和反序列化。下面以 IsQuota 属性为例,自定义 Boolean 类型的序列化和反序列化操作。

    1)   首先定义个 BoolConvert 类,继承于 Newtonsoft.Json.JsonConverter

    /// <summary>

    /// 自定义 Boolean 类型转换。

    /// </summary>

    public class BoolConvert : JsonConverter

    {

        private static readonly string[] _values = { "", "" };

     

        public override bool CanConvert(Type objectType)

        {

            return true;

        }

     

        //序列化时被调用

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

        {

            if (value == null)

                writer.WriteNull();             //输出:null

            else if ((bool)value)

                writer.WriteValue(_values[0]);  //输出:是

            else

                writer.WriteValue(_values[1]);  //输出:否

        }

     

        //反序列化时被调用

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)

        {

            //反序列化成员是否为 null

            if (reader.TokenType == JsonToken.Null)

            {

                if (!IsNullableType(objectType))

                    throw new Exception("序列化成员不能为 null ");

                return null;

            }

            else if (reader.TokenType == JsonToken.String)  //为字符型,应该是“是|否”

            {

                string val = reader.Value.ToString();

                if (val == _values[0])

                    return true;

                else if (val == _values[1])

                    return false;

            }

            else if (reader.TokenType == JsonToken.Integer) // int 型,应该是:0|1

            {

                return Convert.ToInt32(reader.Value) != 0;  //非零即真

            }

            throw new Exception("反序列化不支持的 boolean 类型");

        }

     

        //判断是否为可空类型

        private bool IsNullableType(Type type)

        {

            if (type == null)

                throw new ArgumentNullException("type");

            return type.BaseType.FullName == "System.ValueType" && type.GetGenericTypeDefinition() == typeof(Nullable<>);

        }

    }

     

    2)   修改 Goods 类,添加 JsonConverter 特性。

    /// <summary>

    /// 是否限购

    /// </summary>

    [JsonConverter(typeof(BoolConvert))]

    public bool IsQuota { get; set; }

     

    3)   序列化

    goods[0].IsQuota = true;

    string jsonStr8_1 = JsonConvert.SerializeObject(goods);

    结果:[{"GoodsId":1,"Price":0.0,"IsQuota":"","Status":"Online","CreateTime":"0001-01-01T00:00:00","OrdersDetail":null}]

     

    4)   反序列化(字符型)

    string jsonStr8_2 = "[{"IsQuota":""}]";

    Goods[] jsonObj8_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr8_2);

    结果:

    clip_image003

     

    5)   反序列化(int 型)

    string jsonStr8_3 = "[{"IsQuota":1}]";

    Goods[] jsonObj8_2 = JsonConvert.DeserializeObject<Goods[]>(jsonStr8_3);

    结果:

    clip_image004

     

    9.   使用 DefaultContractResolver(契约分解器)指定序列化成员

    我们可以从 DefaultContractResolver 类派生一个自定义成员分解器类,重写 CreateProperties() 方法完成对每个序列化成员的操作,首先新建一成员契约解析器”类,例如:

    /// <summary>

    /// 成员契约解析器。

    /// </summary>

    public class MemberContractResolver : DefaultContractResolver

    {

        public string[] Props { get; set; }

     

        public bool IsRetain { get; set; }

     

        /// <summary>

        /// 构造方法。

        /// </summary>

        /// <param name="props">指定的成员名称数组。</param>

        /// <param name="isRetain">是否保留指定成员,true:保留;false:不保留。</param>

        public MemberContractResolver(string[] props, bool isRetain)

        {

            this.Props = props;

            this.IsRetain = isRetain;

        }

     

        //创建 JsonProperty 集合

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)

        {

            List<JsonProperty> list = base.CreateProperties(type, memberSerialization) as List<JsonProperty>;

            //顺便设置下日期格式化

            IsoDateTimeConverter dtConverter = new IsoDateTimeConverter() { DateTimeFormat = "yyyy-dd-MM HH:mm:dd" };

            list.ForEach(o =>

            {

                if (o.PropertyType == typeof(DateTime))

                    o.Converter = dtConverter;

            });

            //输出包含或不包含的指定的成员

            if (this.IsRetain)

                return list.Where(o => Props.Contains(o.PropertyName)).ToList();

            else

                return list.Where(o => !Props.Contains(o.PropertyName)).ToList();

        }

    }

     

    1)   序列化包含指定成员

    JsonSerializerSettings serializer6 = new JsonSerializerSettings();

    serializer6.ContractResolver = new MemberContractResolver(new string[] { "GoodsName" }, true);

    string jsonStr9_1 = JsonConvert.SerializeObject(goods, serializer6);

    结果:[{"GoodsName":null}]

     

    2)   序列化不包含指定成员

    JsonSerializerSettings serializer7 = new JsonSerializerSettings();

    serializer7.ContractResolver = new MemberContractResolver(new string[] { "GoodsName" }, false);

    string jsonStr9_2 = JsonConvert.SerializeObject(goods, serializer7);

    结果:[{"GoodsId":0,"Price":125.0,"IsQuota":false,"Status":"Online","CreateTime":"2018-25-04 15:35:25","OrdersDetail":null}]

     

    10.  使用 JsonSerializer 对象序列化与反序列化

    序列化与反序列化除了使用 JsonConvert 这个静态类的 SerializeObject()DeserializeObject() 方法,还可以使用 JsonSerializer 对象的 Serialize()Deserialize() 方法,不过这两个方法用起来比较麻烦,所有不建议使用,知道下就好了。

    序列化与反序列化:

    JsonSerializer serializer2 = new JsonSerializer();

    using (StringWriter textWriter = new StringWriter())

    {

        using (JsonTextWriter jsonWriter = new JsonTextWriter(textWriter))

        {

            //这里可以使用 JsonTextWriter 对象进行序列化相关设置

            serializer2.Serialize(jsonWriter, goods);

        }

        string jsonStr10_1 = textWriter.ToString();

        using (TextReader textReader = new StringReader(jsonStr10_1))

        {

            using (JsonTextReader jsonTextReader = new JsonTextReader(textReader))

            {

                //这里可以使用 JsonTextReader 对象进行反序列化相关设置

                object obj = serializer2.Deserialize(jsonTextReader);

            }

        }

    }

    序列化:

    [{"GoodsId":0,"GoodsName":null,"Price":125.0,"IsQuota":false,"Status":"Online","CreateTime":"2018-04-25T22:10:09.4901712+08:00","OrdersDetail":null}]

    反序列化:

    clip_image006

  • 相关阅读:
    matplotlib基础汇总_03
    matplotlib基础汇总_02
    matplotlib基础汇总_01
    水果系统(面向过程,面向对象)
    给定几位数,查看数根(使用函数实现)
    定义函数,给定一个列表作为函数参数,将列表中的非数字字符去除
    学生管理系统-明日学院的
    四平方和
    四位玫瑰数
    学生成绩表数据包括:学号,姓名,高数,英语和计算机三门课成绩,计算每个学生总分,每课程平均分,最高分和最低分
  • 原文地址:https://www.cnblogs.com/abeam/p/8930687.html
Copyright © 2011-2022 走看看