Ø 简介

接着前一篇 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 属性为例,自定义 B o olean 类型的序列化和反序列化操作。

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) 修改 G oods 类,添加 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