当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json)。JavaScriptSerializer是微软官方提供的一种方法,所以如果你用的是asp.net mvc,在Action中如果你返回的语句写的是”return Json(xxx);“,其实你用的就是JavaScriptSerializer方式。现在更多的人选择的是Json.net,因为它为用户提供了更加清晰地使用体验,清晰在哪?本文主要就是带你走进它们的世界。

JavaScriptSerializer与Json.net

序列化

我们先定义一个测试用的简单类--Person:

  1 public class Person
2 {
3 public string Name;
4 public int Age;
5 public Guid TokenId;
6 public DateTime RegTime;
7 public Person Child;
8 public Person Friend;
9 }

类中的成员仅用来区分不同的变量类型。我们分别以JavaScriptSerializer和Json.net来序列化:

  1 var person = new Person
2 {
3 Age = 28,
4 Name = "李玉宝<yubaolee:>",//故意添加特殊字符
5 RegTime = DateTime.Now,
6 TokenId = Guid.NewGuid(),
7 Child = new Person
8 {
9 Age = 1,
10 Name = "baby",
11 RegTime = DateTime.Now,
12 TokenId = Guid.NewGuid()
13 }
14 }; //注意这里面的Friend没有赋值,默认为空
15
16 JavaScriptSerializer serializer = new JavaScriptSerializer();
17 var jsstr = serializer.Serialize(person); //使用JavaScriptSerializer序列化
18 string newtonstr = JsonConvert.SerializeObject(person); //使用Json.net序列化

JavaScriptSerializer序列化是先生成一个对象,然后调用它的成员函数Serialize进行序列化;

Json.net直接使用提供的静态成员JsonConvert.SerializeObject进行序列化;

两者使用都比较简单,Json.net调用起来方便那么一丢丢!我们来看一下控制台输出结果:

上面绿色为JavaScriptSerializer的结果,下面黄色背景为Json.net的结果,这里需要注意几个地方:

1、 JavaScriptSerializer序列化后的时间格式:"\/Date(1441813200214)\/" 表示的是1970年1月1日(DateTime的最小值)到date实际表示的日期之差的总毫秒数。通常我们需要把它转成标准的时间格式。可以用下面的方法进行字符串处理:

  1 jsstr = Regex.Replace(jsstr, @"\\/Date\((\d+)\)\\/", match =>
2 {
3 DateTime dt = new DateTime(1970, 1, 1);
4 dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
5 dt = dt.ToLocalTime();
6 return dt.ToString("yyyy-MM-dd HH:mm:ss");
7 });

处理完成后的效果:

当然,你还可以通过使用继承JavaScriptConverter的方式,下面反序列化中会具体提及到这种方式。

Json.net默认生成的日期也不方便客户端阅读,需要简单的处理一下:

  1 string newtonstr = JsonConvert.SerializeObject(p, Formatting.Indented,
2 new IsoDateTimeConverter() {DateTimeFormat = "yyyy-MM-dd HH:mm:ss"});

2、JavaScriptSerializer序列化会对特殊字符(如<>等)进行编码,比如上面的\u003c \u003e,很多人看到这个的时候,第一感觉就是太扯蛋了,接下来就是各种百度,怎么把这个转成正常的”<>”。实际上你不用做任何操作,这是标准的JS编码方式,前端会自行处理这个问题。比如:

  1 <script type="text/javascript">
2 var str = 'yubaolee <yubaolee>'
3 var str2 = 'yubaolee \u003cyubaolee\u003e';
4 alert(str == str2); //结果为true
5 </script>

附:如果你真的不明白\u003c这到底是个什么玩意,请移步:字符编码

从上面两点可以看出,JavaScriptSerializer序列化出来的JSON字符串容易给人造成一些困惑,而Json.net完全没有上面的两种情况处理。所以现在很多人都在用Json.net,但从Html标准的角度上来看,JavaScriptSerializer序列化出来的结果更符合Html的要求。不过为了操作习惯,还是建议使用Json.net。

反序列化

我们分别用两种方式对上面已经成功序列化的两个字符串进行反序列化:

  1 //对JavaScriptSerializer生成的字符串进行反序列化
2 //使用JavaScriptSerializer方式
3 var jsperson = serializer.Deserialize<Person>(jsstr);
4 //使用Json.net方式
5 var newtonperson = JsonConvert.DeserializeObject<Person>(jsstr);
6
7 //对Json.net生成的字符串进行反序列化
8 var jsperson2 = serializer.Deserialize<Person>(newtonstr);
9 var newtonperson2 = JsonConvert.DeserializeObject<Person>(newtonstr);

通过运行会发现4个反序列化代码都能正常运行,而不是像以前某些前辈说的,JavaScriptSerializer序列化的串只能用它反序列化,Json.net序列化的串只能用Json.net来反序列化。

上面反序列化的字符串是程序生成的,能正常反序列化不足为奇。但通常我们要反序列化的字符串是客户提交到服务器上面来的串,他们通常是不完整的,或有些还会出现类型不符的情况。比如:

  1 string noChildStr =
2 "{\"Name\":\"李玉宝<yubaolee:>\"," +
3 "\"Age\":28," +
4 "\"RegTime\":\"2015-09-11 00:10:48\"," +
5 "\"Friend\":null}";
6
7 var jsperson = new JavaScriptSerializer().Deserialize<Person>(noChildStr);
8 var newtonperson = JsonConvert.DeserializeObject<Person>(noChildStr);

注意这个字符串中,没有TokenId,没有Child,而且Friend为null。看一看结果:

两个都很智能嘛!解析的结果全部是我们想要的内容。但如果像下面这样呢?

string noChildStr =
"{\"Name\":\"李玉宝<yubaolee:>\"," +
"\"Age\":28," +
"\"RegTime\":\"2015-09-11 00:10:48\"," +
"\"Friend\":null," +
"\"TokenId\":null}"; //注意这个TokenId为空

在运行的时候,程序会直接报错。

错误的内容很容易理解,因为我们把一个null赋值给Guid类型,肯定会出错。在实际的项目操作过程中还有可能出现把一个内容为空的字符串传给Datetime类型,把一个数字传给GUID等各种参数传递的问题,关键是我们还要来处理它们,而不能使程序直接报错崩溃。

1、在JavaScriptSerializer中有一个JavaScriptConverter可以来处理这些问题,它是用来实现JSON序列化中自定义类型的处理。比如下面的代码,就是处理把一个null赋值给Guid的情况:

  1 public class PersonJsConverter : JavaScriptConverter
2 {
3 public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
4 {
5 Person person = new Person();
6
7 object value = null;
8 if (dictionary.TryGetValue("TokenId", out value) && value != null)
9 person.TokenId = (Guid) value;
10 //其他字段略...
11
12 return person;
13 }
14
15 public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
16 {
17 Dictionary<string, object> dic = new Dictionary<string, object>();
18 var node = obj as Person;
19 if (node == null)
20 return null;
21 if (!string.IsNullOrEmpty(node.Name))
22 dic.Add("Name", node.Name);
23 //其他字段略...
24 return dic;
25 }
26
27 public override IEnumerable<Type> SupportedTypes
28 {
29 get
30 {
31 return new Type[] { typeof(Person) };
32 }
33 }
34 }

然后在反序列化之前,我们把这个转换注册到实体对象中,这时再执行,程序就一切正常了:

JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new PersonJsConverter(), }); var deserialize = serializer.Deserialize<Person>(noChildStr);

2、在使用Json.net时,采用了一种更加优雅的方式来处理这个问题--JsonConverter,它可以单独处理一个指定的类成员变量。这样就不用像上面的JavaScriptConverter一样处理整个类的所有成员。代码如下:

  1 public class GuidConverter : JsonConverter
2 {
3 public override bool CanConvert(Type objectType)
4 {
5 return objectType.IsAssignableFrom(typeof(Guid));
6 }
7
8 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
9 {
10 try
11 {
12 return Guid.Parse(reader.Value.ToString());
13 }
14 catch
15 {
16 //如果传进来的值造成异常,则赋值一个初值
17 return Guid.Empty;
18 }
19 }
20
21 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
22 {
23 serializer.Serialize(writer, value);
24 }
25 }

值得注意的是JsonConverter是一个Attribute,所以要在类成员上面添加一个特性:

  1  public class Person
2 {
3 public string Name;
4 public int Age;
5 [JsonConverter(typeof(GuidConverter))]
6 public Guid TokenId { get; set; }
7 public DateTime RegTime;
8 public Person Child;
9 public Person Friend;
10 }

这时,再运行程序时,TokenId就会被赋上一个初始的值。看来在反序列化中,Json.net还是更胜一筹。

性能

这是网上给出来两个的性能比较:

综上,在不考虑系统对第三方控件引用的要求情况下,尽量使用Json.net来进行对象序列化处理。

其他常用的序列化方法

说了半天,回顾一下序列化的定义:

序列化:将对象转换成字节流的过程,这样就可以轻松将对象保存在磁盘文件或数据库中。

反序列化:序列化的逆过程,就是将字节流转换回原来的对象的过程。

其他各种格式序列化的方法请参考:

序列化与反序列化,及Json序列化反序列化

谈谈:.Net中的序列化和反序列化

.Net深入实战系列—JSON序列化那点事儿的更多相关文章

  1. .Net深入实战系列—JSON序列化那点事儿

    序 当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json).JavaScriptSerializer ...

  2. JSON序列化那点事儿

    JSON序列化那点事儿 序 当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json).JavaScri ...

  3. SpringBoot基础实战系列(二)springboot解析json与HttpMessageConverter

    SpringBoot解析Json格式数据 @ResponseBody 注:该注解表示前端请求后端controller,后端响应请求返回 json 格式数据前端,实质就是将java对象序列化 1.创建C ...

  4. Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解

    Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全   Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...

  5. WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化

    WPF中的常用布局   一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...

  6. 小解系列-自关联对象.Net MVC中 json序列化循环引用问题

    自关联对象在实际开发中用的还是比较多,例如常见的树形菜单.本文是自己实际的一个小测试,可以解决循环引用对象的json序列化问题,文笔不好请多见谅,如有错误请指出,希望有更好的解决方案,一起进步. 构造 ...

  7. SpringBoot系列: Json的序列化和反序列化

    ============================= 控制 json 序列化/反序列化=============================1. @JsonIgnoreProperties的 ...

  8. [CXF REST标准实战系列] 一、JAXB xml与javaBean的转换(转)

    转自:[CXF REST标准实战系列] 一.JAXB xml与javaBean的转换 文章Points: 1.不认识到犯错,然后得到永久的教训. 2.认识JAXB 3.代码实战 1.不认识到犯错,然后 ...

  9. Jaskson精讲第7篇-类继承关系下的JSON序列化与反序列化JsonTypeInfo

    Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的, ...

随机推荐

  1. linux常见故障处理

    目录 一. 文件和目录类 1.1 File exist 文件已经存在 1.2 No such file or directory 没有这个文件或目录(这个东西不存在) 1.3 command not ...

  2. nginx rewrite规则笔记

    优先级 在nginx的location和配置中location的顺序没有太大关系.正location表达式的类型有关.相同类型的表达式,字符串长的会优先匹配. 第一优先级:等号类型(=)的优先级最高. ...

  3. luoguP1941-

    飞扬的小鸟 20分&50分: #include<iostream> #include<cstdio> #include<cstring> #include& ...

  4. PADS Layout VX.2.3 设置测量精度

    操作系统:Windows 10 x64 工具1:PADS Layout VX.2.3 Pin #7.#8的实际距离是0.65mm,但是测量的结果却是0.7mm.为什么呢?这是由于测量精度的设置不恰当造 ...

  5. Cross-Origin Resource Sharing(CORS)详解,CORS详解,CORS原理分析

    Keywords CORS, 跨域,JS跨域调用,Ajax CORS 跨域,跨域详解,CORS跨域原理 Cross-Origin Resource Sharing详解 Cross-Origin Res ...

  6. 【Linux】日志分析工具grep sed sort

    遇到一个问题,在查询日志时发现,服务器上打印的文件有很多个,每个都存储了一部分日志, 需要将日志按照时间排序,并显示所有日志. 原命令: grep -h  searchContent */*log 搜 ...

  7. 路漫漫其修远兮,吾将上下而求索--2019OKR规划

    一.前言 加入博客园半年多,认识了很多优秀上进,乐于分享的人,我的男神:EdisonZhou,还有张队长,叶伟民,腾飞,梁桐铭 等等. 半年来写了26篇随笔,我的第一篇随笔 C# DynamicObj ...

  8. java集合遍历的几种方式总结及比较

    集合类的通用遍历方式, 用迭代器迭代: Iterator it = list.iterator(); while(it.hasNext()) { Object obj = it.next(); }   ...

  9. 使用Nginx反向代理和内容替换模块实现网页内容动态替换功能

    2016年11月21日 10:30:00 xian_02 阅读数:10943   Nginx是一款轻量级高性能服务器软件,虽然轻量,但功能非常强大,可用于提供WEB服务.反向代理.负载均衡.缓存服务. ...

  10. 微信小程序之支付密码输入demo

    在小程序中实现支付密码的输入,要解决几个问题: 1.小程序要想唤起键盘,必须要借助input控件.通过input控件和其属性focus来唤起和隐藏输入键盘. 2.要让input控件不可见.让光标和输入 ...