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

结果:

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 的高级用法

上一篇:jquery获取元素(父级的兄弟元素的子元素)


下一篇:JSON.stringify常见用法