Newtonsoft.Json 的高级用法

时间:2022-07-08 07:00:37

Ø  简介

接着前一篇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);

结果:

Newtonsoft.Json 的高级用法

 

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

结果:

Newtonsoft.Json 的高级用法

 

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.*Exception(感觉这个值没什么用?)

下面模拟循环引用场景(修改 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);

结果:

Newtonsoft.Json 的高级用法

 

5)   反序列化(int 型)

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

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

结果:

Newtonsoft.Json 的高级用法

 

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

反序列化:

Newtonsoft.Json 的高级用法