JSON序列化那点事儿

当前主流的序列化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 { get; set; }
  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. JavaScriptSerializer serializer = new JavaScriptSerializer();
  16. var jsstr = serializer.Serialize(person);                //使用JavaScriptSerializer序列化
  17. 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. //对Json.net生成的字符串进行反序列化
  7. var jsperson2 = serializer.Deserialize<Person>(newtonstr);
  8. 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. var jsperson = new JavaScriptSerializer().Deserialize<Person>(noChildStr);
  7. var newtonperson = JsonConvert.DeserializeObject<Person>(noChildStr);

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

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

  1. string noChildStr =
  2. "{\"Name\":\"李玉宝<yubaolee:>\"," +
  3. "\"Age\":28," +
  4. "\"RegTime\":\"2015-09-11 00:10:48\"," +
  5. "\"Friend\":null," +
  6. "\"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. object value = null;
  7. if (dictionary.TryGetValue("TokenId", out value) && value != null)
  8. person.TokenId = (Guid) value;
  9. //其他字段略...
  10. return person;
  11. }
  12. public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
  13. {
  14. Dictionary<string, object> dic = new Dictionary<string, object>();
  15. var node = obj as Person;
  16. if (node == null)
  17. return null;
  18. if (!string.IsNullOrEmpty(node.Name))
  19. dic.Add("Name", node.Name);
  20. //其他字段略...
  21. return dic;
  22. }
  23. public override IEnumerable<Type> SupportedTypes
  24. {
  25. get
  26. {
  27. return new Type[] { typeof(Person) };
  28. }
  29. }
  30. }

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

  1. JavaScriptSerializer serializer = new JavaScriptSerializer();
  2. serializer.RegisterConverters(new JavaScriptConverter[] { new PersonJsConverter(),  });
  3. 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. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  8. {
  9. try
  10. {
  11. return serializer.Deserialize<Guid>(reader);
  12. }
  13. catch
  14. {
  15. //如果传进来的值造成异常,则赋值一个初值
  16. return Guid.Empty;
  17. }
  18. }
  19. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  20. {
  21. serializer.Serialize(writer, value);
  22. }
  23. }

值得注意的是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中的序列化和反序列化

JSON序列化那点事儿的更多相关文章

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

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

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

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

  3. Newtonsoft.Json 序列化和反序列化 时间格式【转】

    1.JSON序列化 string JsonStr= JsonConvert.SerializeObject(Entity); eg:   A a=new A(); a.Name="Elain ...

  4. [.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) Json 序列化利器 Newtonsoft.Json 及 通用Json类

    [.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) Json 序列化利器 Newtonsoft.Json 及 通用Json类 本节导读: 关于JSON序列化,不能 ...

  5. DotNet的JSON序列化与反序列化

    JSON(JavaScript Object Notation)JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式.在现在的通信中,较多的采用JSON数据格式,JSON有 ...

  6. C#中JSON序列化和反序列化

    有一段时间没有到博客园写技术博客了,不过每天逛逛博客园中大牛的博客还是有的,学无止境…… 最近在写些调用他人接口的程序,用到了大量的JSON.XML序列化和反序列化,今天就来总结下json的序列化和反 ...

  7. 使用JSON.Net(Newtonsoft.Json)作为ASP.Net MVC的json序列化和反序列化工具

    ASP.Net MVC默认的JSON序列化使用的是微软自己的JavaScriptSerializer.性能低不说,最让人受不了的是Dictionary<,>和Hashtable类型居然对应 ...

  8. Windows Phone 六、JSON序列化

    JSON序列化 public class Person { public int Id { get; set; } public string Name { get; set; } public in ...

  9. [MVC_Json序列化]MVC之Json序列化循环引用

    在做MVC项目时,难免会遇到Json序列化循环引用的问题,大致错误如下 错误1:序列化类型为“...”的对象时检测到循环引用. 错误2:Self referencing loop detected f ...

随机推荐

  1. Android在 Alertdialog对话框中点击消失?

    在开发的时候遇到一个问题.就是一触摸对话框边缘外部,对话框会自己主动消失.这个问题非常纠结啊,查找了一下发现从Android 4.0開始.AlertDialog有了变化.就是在触摸对话框边缘外部.对话 ...

  2. UML用例图总结(转)

    用例图主要用来描述“用户.需求.系统功能单元”之间的关系.它展示了一个外部用户能够观察到的系统功能模型图. [用途]:帮助开发团队以一种可视化的方式理解系统的功能需求. 用例图所包含的元素如下: 1. ...

  3. unrecognized selector sent to instance 0x10b34e810

    一个错误: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLEr ...

  4. Java RMI(远程方法调用) 实例与分析

    目的: 通过本文,可以加深对Java RMI的理解,知道它的工作原理,怎么使用等. 也为了加深我自己的理解,故整理成文.不足之处,还望指出. 概念解释: RMI(RemoteMethodInvocat ...

  5. HDU 4435 charge-station (并查集)

    先说下题目的意思: 在一个二维坐标系中有N个点,某人要来个走遍所有点的旅行,但是他的车每次加油后只能走M个单位距离:所以要在这个N点中选一些建立加油站:问题来了:i^th  点 建加油站的花费是  2 ...

  6. 【Linux探索之旅】第一部分第四课:磁盘分区,并完成Ubuntu安装

    内容简介 1.第一部分第四课:磁盘分区,并完成Ubuntu安装 2.第一部分第五课预告:Unity桌面,人生若只如初见 磁盘分区 上一课我们正式开始安装Ubuntu了,但是到了分区的那一步,小编却戛然 ...

  7. 【Java收集的源代码分析】Hashtable源代码分析

    Hashtable简单介绍 Hashtable相同是基于哈希表实现的,相同每一个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时.相同会自己主动增长. Has ...

  8. 使用Python做科学计算初探(转)

    今天在搞定Django框架的blog搭建后,尝试一下python的科学计算能力. python的科学计算有三剑客:numpy,scipy,matplotlib. numpy负责数值计算,矩阵操作等: ...

  9. 第十九章——使用资源调控器管理资源(1)——使用SQLServer Management Studio 配置资源调控器

    原文:第十九章--使用资源调控器管理资源(1)--使用SQLServer Management Studio 配置资源调控器 本系列包含: 1. 使用SQLServer Management Stud ...

  10. IE8/IE9无法启用JavaScript怎么办

    在IE8/IE9 中,有些同学在浏览网页时,收到提示:“需要启用 JavaScript …”,并且会发现网页上某些功能不能用了,比如点击网页里的按钮没反应等等.这个是因为浏览器的JavaScript ...