【Json】1.Newtonsoft—Json.NET常用方法简述
json.net常用方法汇总(可解决日常百分之90的需求)
0.json.net基础用法
首先去官网下载最新的newtonsoft.json.dll(也可以使用vs自带的nuget搜索json.net下载(下载下图第二个))并引用至项目。
- (1)序列化实体类(将实体类对象序列化为json字符串)
using system; using newtonsoft.json; namespace json_net_test { /// <summary> /// 定义一个实体类 /// </summary> public class student { public string name; public int age; public string class; } class program { static void main(string[] args) { //创建实体类对象 student stu = new student { name = "老王", age = 99, class = "三班" }; //开始序列化 string jsonstr = jsonconvert.serializeobject(stu, formatting.indented); console.writeline(jsonstr); } } }
结果:
- (2)反序列化(将json字符串反序列化为实体类对象)
using system; using newtonsoft.json; namespace json_net_test { /// <summary> /// 定义一个实体类 /// </summary> public class student { public string name; public int age; public string class; } class program { static void main(string[] args) { //json字符串 string jsonstr = "{\"name\": \"老王\",\"age\": 99,\"class\": \"三班\"}"; //开始反序列化 student stu = jsonconvert.deserializeobject<student>(jsonstr); } } }
1.序列化与反序列化时忽略某些属性
- (1)忽略类内所有属性
[jsonobject(memberserialization.optin)]用于在序列化与反序列化时忽略一个类里所有的属性,只有当在类内属性上打特性标签[jsonproperty]时才支持序列化与反序列化。所以[jsonobject(memberserialization.optin)]常用于与[jsonproperty]配合使用。
例:
[jsonobject(memberserialization.optin)] public class person { public int age { get; set; } [jsonproperty] public string name { get; set; } public string sex { get; set; } public bool ismarry { get; set; } public datetime birthday { get; set; } }
- (2)序列化所有属性(默认)
默认实体类上默认打着[jsonobject(memberserialization.optout)]特性标签(可以省略不写),如果要忽略某些属性,要在属性上打[jsonignore]。
例:
[jsonobject(memberserialization.optout)] public class person { public int age { get; set; } public string name { get; set; } public string sex { get; set; } [jsonignore] public bool ismarry { get; set; } public datetime birthday { get; set; } }
- (3)动态控制实体类属性的是否忽略序列化(默认)
当某些条件下需要序列化a属性和b属性,某些情况下需要忽略a属性与b属性,我们该怎么做?
答:使用jsonserializersettings设置某实体类对象要忽略序列化的属性(配合if与else控制属性的动态忽略)。
例:以下方式忽略p对象的age属性与ismarry属性:
jsonserializersettings jsetting=new jsonserializersettings(); jsetting.contractresolver = new limitpropscontractresolver(new string[] { "age", "ismarry" }); console.writeline(jsonconvert.serializeobject(p, formatting.indented, jsetting));
2.默认值处理
- (1)设置属性默认值
在属性上打 [defaultvalue("xxx")]
3.空值处理
- (1)不序列化为null的属性(使用jsonserializersettings方式)
person p = new person { room = null, age = 10, name = "张三丰", sex = "男", ismarry = false, birthday = new datetime(1991, 1, 2) }; jsonserializersettings jsetting=new jsonserializersettings(); jsetting.nullvaluehandling = nullvaluehandling.ignore; console.writeline(jsonconvert.serializeobject(p, formatting.indented, jsetting));
ps:使用这种方式可能bool为false的也无法序列,最后的结果只包含birthday、sex、name、age。
- (2)不序列化为null的属性(使用特性标签方式)
[jsonproperty(nullvaluehandling=nullvaluehandling.ignore)] public room room { get; set; }
4.序列化私有成员
因为默认只序列化public的成员,所以如果想序列化private成员,要在实体类的属性上打[jsonproperty]标签。
[jsonproperty] private int height { get; set; }
5.自定义序列化名称
在序列化与反序列化时可以自定义序列化出字符串的属性名称,如下代码可以将实体类的name属性序列化为cname属性,并且可以将json中的cname反序列化为当前实体类的name属性。(双向)
[jsonproperty(propertyname = "cname")] public string name { get; set; }
6.日期处理
- (1)解决方案1:在可以动model代码的情况下
系统自带的datetime会格式化成iso日期标准,但是实际使用过程中大多数使用的可能是yyyy-mm-dd 或者yyyy-mm-dd hh:mm:ss两种格式的日期,解决办法是可以将datetime类型改成string类型自己格式化好,然后在序列化。
例:
[jsonproperty(propertyname = "starttime")]//因为默认只序列化public属性,所以要打上jsonproperty标签并且声明名称 private string m_starttime{get;set;} [jsonignore]//这个标签用于在序列化与反序列化时忽略starttime属性 public datetime starttime { get{ return convert.todatetime(m_starttime); } set { datetime time = value; m_starttime = time.tostring("yyyy-mm-dd");//这里写自己想要的格式 } }
ps:代码思路是不去序列化starttime属性,而去序列化string类型的m_starttime属性(m_starttime相当于starttime属性的私有字段)。
- (2)解决方案2:使用datetimeconverterbase
json.net提供了isodatetimeconverter日期转换这个类,可以通过jsnconverter实现相应的日期转换
[jsonconverter(typeof(isodatetimeconverter))] public datetime birthday { get; set; }
但是isodatetimeconverter日期格式(yyyy-mm-ddthh:mm:ss)不是我们想要的,我们可以继承该类实现自己的日期
例:
public class chinadatetimeconverter : datetimeconverterbase { private static isodatetimeconverter dtconverter = new isodatetimeconverter { datetimeformat = "yyyy-mm-dd" }; public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer) { return dtconverter.readjson(reader, objecttype, existingvalue, serializer); } public override void writejson(jsonwriter writer, object value, jsonserializer serializer) { dtconverter.writejson(writer, value, serializer); } }
使用方式:
[jsonconverter(typeof(chinadatetimeconverter))] public datetime birthday { get; set; }
7.以驼峰命名法序列化
有时我们会碰到这种需求,比如我们代码里实体类型的属性名称均是以大写字母开头,如name、starttime等,但是要求我们序列出的json字符串的属性名称要以小写字母开头,如name、starttime、endtime等。我们可以使用如下代码解决
jsonserializersettings setting = new jsonserializersettings(); setting.contracresolver = new camelcasepropertynamescontractresolver(); string jsonstr = jsonconvert.serializeobject(p, newtonsoft.json.formatting.indented, setting);
这样子的话,在序列实体类对象p的属性时,属性名称将由personname转换为personname。
8.枚举的序列化
枚举默认序列化为枚举的int值,如果想要序列化为枚举string值,使用如下方式
9.将多个数据类型序列化为1个json对象(序列化匿名类)
有时我们有这样的需求,对方要求我们传输过去的json字符串要包含我们多个实体类型的信息,笨方法就是重新构建一个符合要求的实体类型,但是我们又更好的方法,我们可以使用匿名类,把json需要的信息均放在匿名类中,我们可以对匿名类进行序列化。
例:
list<model> list1 = new list<model>(); list<model2> list2 = new list<model2>(); string name = "名字"; string address = "xx"; list<string> info = new list<string>() { name, address }; var json = new { information = info, jsonlist1 = list1, jsonlist2 = list2 };
我们只需要对上面的匿名对象“json”序列化即可。
10.使用jsonconverter自定义属性序列化规则(json格式转换器)
- (1)将属性值由double类型序列化时转为字符串类型
public class doubletostringconverter : jsonconverter { //表示反序列化时不执行该转换器 public override bool canread => false; //表示序列化时执行该转换器 public override bool canwrite => true; //判断执行条件(当属性的值为double类型时才使用转换器) public override bool canconvert(type objecttype) { return objecttype == typeof(double); } //因为public override bool canread => false;,所以不用实现反序列化时的转换方法 public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer) { throw new notimplementedexception(); } /// <summary> /// 序列化时执行的转换 /// </summary> /// <param name="writer">可以用来重写值</param> /// <param name="value">属性的原值</param> /// <param name="serializer">就是那个serializer对象</param> public override void writejson(jsonwriter writer, object value, jsonserializer serializer) { double v = (double)value; writer.writevalue(v.tostring()); } }
使用方式:
[jsonconverter(typeof(doubletostringconverter))] public double count{get;set;}
ps:这样子,就可以把原本序列化出的json字符串 count : 12.3 转化为 count : "12.3"
ps:[jsonconverter(typeof(doubletostringconverter))]也可以打在类上,表示全局设置
- (2)枚举转换为int字符串
为什么要进行这样的转换呢?
因为枚举类型在序列化时默认序列化为枚举的int类型,即如下代码:
/// <summary> /// 自定义一个枚举类型 /// </summary> public enum myenum { aaa = 1, bbb = 2, ccc = 3 } /// <summary> /// 实体类(类内有一个枚举类型的属性myenumprop) /// </summary> public class person { public myenum myenumprop { get; set; } } class program { static void main(string[] args) { person p = new person() { myenumprop = myenum.ccc }; //json字符串 string jsonstr = jsonconvert.serializeobject(p); //开始反序列化 console.writeline(jsonstr); console.readline(); } }
结果为:
有时候会有这样的需求,序列化出的属性值均要为字符串格式,即要将上图结果的3改为"3"。这时候就需要自定义转换了!
代码如下:
public class enumtointstringconverter : jsonconverter { //反序列化时不执行 public override bool canread => false; //序列化时执行 public override bool canwrite => true; //控制执行条件(当属性的值为枚举类型时才使用转换器) public override bool canconvert(type objecttype) { return objecttype == typeof(enum); } //因为public override bool canread => false;,所以不用实现反序列化时的转换方法 public override object readjson(jsonreader reader, type objecttype, object existingvalue, jsonserializer serializer) { throw new notimplementedexception(); } /// <summary> /// 序列化时执行的转换 /// </summary> /// <param name="writer">可以用来重写值</param> /// <param name="value">属性的原值</param> /// <param name="serializer">就是那个serializer对象</param> public override void writejson(jsonwriter writer, object value, jsonserializer serializer) { enum e = (enum)value; int v = convert.toint32(e); writer.writevalue(v.tostring()); } }
使用方法同上例。
下一篇: C# 通过反射获取winform上的控件