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);
结果:

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.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);
结果:

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}]
反序列化:

Newtonsoft.Json 的高级用法的更多相关文章
- 记录Newtonsoft.Json的日常用法
		
最近在做一个使用基于.net mvc 实现前后台传输Json的实例.网上找了一些资料.发现在开发的时候,许多的数据交互都是以Json格式传输的.其中涉及序列化对象的使用的有DataContractJs ...
 - JSON.parse()与JSON.stringify()高级用法
		
JSON.parse()与JSON.stringify是将JSON对象与字符串互相转换的方法,它们还有一些参数可以让我们在实际应用中更加方便,现在介绍一下它们的高级用法 JSON.parse() JS ...
 - Newtonsoft.Json 的解析用法。
		
JsonView是查看和分析json的利器,目录下的Newtonsoft.Json.dll ,我们可以当第三方引用之. >>> //想服务器端发送请求,获取订单信息 myReques ...
 - 记一次 Newtonsoft.Json 巧妙的用法(C#)
		
数据添加的功能 有一个表格提交数据如下: 是否选择和文本值.分开保存到数据库太麻烦.取得时候也麻烦 想到了存成json数据.一个字段就可以了. html代码: <table class=&quo ...
 - Newtonsoft.Json 的基本用法
		
Ø 前言 说起 C# 对 JSON 的操作(序列化与反序列化),大家都会想到 JavaScriptSerializer.DataContractJsonSerializer 与 Newtonsoft ...
 - 理解JSON.stringify()高级用法
		
一:JSON.stringify() 该方法是把javascript对象转换成json字符串. 基本语法:JSON.stringify(value, [, replacer], [, space]) ...
 - Newtonsoft.Json高级用法之枚举中文转义
		
最近看博客园中 焰尾迭的两篇关于"Newtonsoft.Json高级用法"的文章受到了很多人的评论,一度登入到头条推荐. 今天我就不再重复焰尾迭博文中的一些提过的Newtonsof ...
 - Newtonsoft.Json高级用法(转)
		
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
 - 【转】 Newtonsoft.Json高级用法
		
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
 
随机推荐
- Codeforces | CF1041F 【Ray in the tube】
			
昨天晚上全机房集体开\(Div2\),因为人傻挂两次\(B\)题的我开场就\(rank2000+\dots qwq\)于是慌乱之中的我就开始胡乱看题(口胡),于是看了\(F\dots\)(全机房似乎也 ...
 - 540. Single Element in a Sorted Array
			
题目大意: 给你一个由小到大排好序的数组,里面只有一个数出现了一次,其他数都出现了两次,要求找出那个只出现一次的数,而且时间复杂度为O(logn) 题目思路: 说实话一开始没想到,因为几乎每个数都出现 ...
 - 题解 P4512 【【模板】多项式除法】
			
题目地址 前言 原理有大佬写了 所以蒟蒻只讲下本题的代码细节 我看懂的大佬博客:博客地址 因为可能知道了大致的步骤还有很多细的地方不理解导致写的时候要花很久并且看到大佬们好像都是用递归写的希望能有帮助 ...
 - loj6157 A ^ BProblem (并查集)
			
设s[x][i]表示从根到x的异或和在第i位上的值(0/1),(a,b,i)表示a到b的异或和在第i位上的值那么就有(a,b,i)=(s[a][i]^s[b][i]^s[lca][i]^s[lca][ ...
 - 2018 ICPC 焦作网络赛 E.Jiu Yuan Wants to Eat
			
题意:四个操作,区间加,区间每个数乘,区间的数变成 2^64-1-x,求区间和. 题解:2^64-1-x=(2^64-1)-x 因为模数为2^64,-x%2^64=-1*x%2^64 由负数取模的性质 ...
 - codeforces #530 D(Sum in the tree) (树上贪心)
			
Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root has index 11. Each ve ...
 - javascript Object的新方法
			
今天复习es6,又看到Object的一堆方法,与es5的表现又有不一致,耗费了一整天,整理一下: 前几天在司徒正美的书里又看到了es5 Object的字眼,为了向下兼容,大神们也是牛逼的整理出一系列i ...
 - A1131. Subway Map (30)
			
In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...
 - [nowcoderACM_223C][区区区间间间]
			
题目链接 思路 考虑用单调栈,栈顶为最大元素.当得到一个新值得时候,将这个值宇栈顶比较.因为栈顶是前面的最大元素.所以只要当前元素比栈顶大,那么肯定比前面的都大.只要将这个元素乘上前面的个数就行了. ...
 - R语音:解决cor.test报错的 'y'必需是数值矢量
			
'y'必需是数值矢量,产生该类报错可能是含有NA值. 只需要在该数值上加入as.double函数即可.见下命令: ##先测试是不是数值型 is.numeric(data[,2]) #[1] FALSE ...