Ø 简介
接着前一篇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);
结果:
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);
结果:
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);
结果:
5) 反序列化(int 型)
string jsonStr8_3 = "[{\"IsQuota\":1}]";
Goods[] jsonObj8_2 = JsonConvert.DeserializeObject<Goods[]>(jsonStr8_3);
结果:
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}]
反序列化: