在ASP.NET AJAX中,客户端的序列化与反序列能力由Sys.Serialization.JavaScriptSerializer类的serialize和deserialize两个静态方法提供。在服务器端,所有的序列化与反序列化能力,包括类型之间的转换,对于开发人员来说都是由JavaScriptSerializer类的几个方法实现的。从前一片文章里我们已经知道了两个辅助的类:JavaScriptTypeResolver和JavaScriptConverter,他们的作用分别是“映射类与类标识”,以及“提供特定类的序列化与反序列化能力”。在以后的文章里,我将通过两个示例来演示这两个类在Web Services Access中直接或者间接的使用方式。

在某些情况下,我们还是需要使用JavaScriptSerializer类的方法来操作一个类型,例如使用JavaScriptConverter来自定义特定类的序列化或者反序列化,就需要使用JavaScriptSerializer类的方法,因此我们这次就详细看一下这个类的能力。

在JavaScriptSerializer中,我们可以看到下面可以使用的方法或者构造函数,它们都是实例方法:

Icon Member Description
JavaScriptSerializer() 构造函数,用于创建一个新的JavaScriptSerializer对象,不指定JavaScriptTypeResolver
JavaScriptSerializer(JavaScriptTypeResolver) 构造函数,用于创建一个新的JavaScriptSerializer对象,并使用指定的JavaScriptTypeResolver来映射特定类型与标识字符串。
ConvertToType<T>(Object) 将给定对象转化成类型T。
Deserialize<T>(String) 将JSON字符串转化为类型T。
DeserializeObject(String) 将JSON字符串转化为一个对象。
MaxJsonLength 获取或者设置序列化时能够接受的JSON字符串的最大长度。
RecursionLimit 获取或者设置在反序列化JSON字符串时递归的最大深度。
RegisterConverters(IEnumerable<JavaScriptConverter>) 注册序列化过程中使用的JavaScriptConveter对象。
Serialize(Object) 将一个对象序列化成JSON字符串。
Serialize(Object, StringBuilder) 将一个对象序列化到一个StringBuilder中。

在这里我们主要来看一下ConvertToType,Deserialize,DeserializeObject和Serialize的两个重载方法。

1、ConvertToType<T>(Object)

ConvertToType<T>(Object)方法的作用是将一个Object对象转换为指定的对象T。这个Object对象主要的转换,在其内部是直接调用了ObjectConverter.ConvertObjectToType(Object o, Type type, JavaScriptSerializer serializer)方法实现。ObjectConverter.ConvertObjectToType方法主要逻辑依次如下:

  1. 如果参数o为null,并且type为可以null的类型(例如引用类型,和.NET 2.0中的Nullable类型),则直接返回null。如果type不是可以为null的类型,但是type是char类型,那么返回'\0'。如果参数o不为null,则将继续下面的逻辑。
  2. 如果参数o是IDictionary<string, object>类型,则调用内部的ObjectConverter.ConvertDictionaryToObject方法将一个Dictionary<string, object>转换为type类型对象。
  3. 如果参数o是IList类型,则会调用内部的ObjectConverter.ConvertListToObject方法将IList类型转换为type类型对象。
  4. 如果type为null,或者参数o已经是type对象了,那么直接返回对象o。
  5. 使用TypeDescriptor.GetConverter方法获得type对应的TypeConverter,如果该TypeConverter能够转换o则转换并返回,否则会使用参数o的TypeConverter先将o转换为字符串(使用ConvertToInvariantString方法),再使用type对应的TypeConverter将该字符串转换为type类型(使用ConvertFromInvariantString方法)并返回。如果o的TypeConverter无法将o转换为字符串,或者type对应的TypeConverter无法将一个字符串转换为type类型,则只能检查o类型是否能够直接赋值给type类型。如果这也不行,那么只能抛出异常了。

  上面的逻辑其实不完整,在它的实现中事实上会在不少地方能够抛出异常,我则省略了这些逻辑的描述。

在最后一步的“复杂”逻辑中,似乎能够使用提供TypeConverter来转换对象,以此自定义序列化与反序列化能力(事实上,如果单独使用这个方法时您的确可以这么做),但是事实上在实际使用中作用并不大。因为序列化与反序列化能力主要是应用在Web Service方法访问上的,而在这里的反序列化过程中很难使这段逻辑“遭遇”特殊的对象(虽然我们能够通过自定义JavaScriptConvetor来“遭遇”这种情况)。在这里,使用TypeConverter是为了转换一些“基础对象”,例如Int32,Double等。另外需要注意的是,我们不能使用ConvertToType方法直接转换客户端序列化的日期对象,因为日期在客户端会被序列化成“"@23552233@"”传递过来,在反序列化时需要做特殊处理。

将IDictionary<string, object>和IList转化成特定对象的逻辑比较重要,尤其是前者。我们先来看一下它的主要逻辑吧:

  1. 如果在这个字典中存在“__type”对应的字符串(如果不是字符串,会将其转换为字符串,但是这种情况毫无意义),则会使用serializer中使用的JavaScriptTypeResolver,以“__type”的值作为类型的标示,以获得真正需要转化为的目标类型。这时,目标对象可能已经是新的类型了,我们称之为realType。
  2. 如果realType类型在serializer中存在对应的JavaScriptConverter,则使用特定的Converter反序列化对象,并返回。
  3. 最后,如果原始的type为字典或泛型字典,则会将这个原始IDictionary<string, object>转换为type对象。否则就会将构造一个realType类型的对象(需要注意的是这个类型必须有无参数的构造函数),然后会通过反射机制为public的属性或者变量(属性优先)。在这里,如果原始IDictionary<string, object>的key相对于目标类型的属性和变量相比有多余,也不会抛出异常。很自然,在将原始IDictionary<string, object>的value转换为目标字典中的value类型,或者目标类型的属性和变量的类型时,会递归调用ObjectConverter.ConvertObjectToType方法。

  事实上,这个IDictionary<string, object>对象代表了一个JSON字符串到特定类型的“中间状态”,上面这段逻辑可以说被大量运用在Web Services方法的访问中,这也就是为什么第一步会判断有没有“__type”的定义,因为这是在客户端指定服务器端特定类型的做法。这种IDictionary<string, object>到Object转换,是反序列化过程的一部分。

相对来说,IList到Object的转换就比较简单了,它能够支持的对象类型有Array,ArrayList,List,List<T>和其余实现IList的类型。注意能够在服务器端反序列化的类型都必须有无参数的构造函数,在转换时依旧会递归调用ObjectConverter.ConvertObjectToType方法。

2、Deserialize<T>(String)

该方法的作用是将一个JSON字符串转化为类型T。

该方法的第一步,是首先将该字符串转化成为一个中间类型。这个类型可能是个基础类型(Int32,Double,DateTime等),或者IDictionary<string, object>与IList的互相嵌套(这就是JSON字符串的表示形式,一般来说,最终目标也是基础类型)。但是需要注意是,在将一个“{...}”形式的字符串片断转换为IDictionary<string, object>之后,如果发现该字典中有关于“__type”的定义,就会调用ObjectConverter.ConvertObjectToType方法立即将其转换为__type表示的类型,在这个过程中会将调用Deserialize<T>(String)方法的JavaScriptSerializer对象在各个操作中进行传递,因此起初在那个JavaScriptSerializer对象中定义的JavaScriptTypeResolver和JavaScriptConverter都会产生效果。

该方法的第二步,就是将第一步所得到的结果,使用ObjectConverter.ConvertObjectToType方法将其转换为目标T了。可以发现,由于JSON字符串中“__type”的作用,还是能够在之前描述过的ObjectConverter.ConvertObjectToType逻辑的第5步中,使TypeConverter起到所需的效果的。如果合理使用,就能够很方便的进行开发。

3、DeserializeObject(String)

该方法可以说是Deserialize<T>(String)方法的一小部分,它也分作两步进行。其中第一步和Deserialize<T>(String)方法第一步作用完全一样,而第二步也是使用了ObjectConverter.ConvertObjectToType方法进行转换。由于和那个方法相比没有指定目标对象T,因此传递给ObjectConverter.ConvertObjectToType方法的第二个参数则为null,也就是说,如果进行到IDictionary<string, object>到Object的转换,如果没有指定“__type”,它将保持不变。至于“[...]”类型的JSON字符串,如果没有指定type,则会默认转换为一个Object数组。

4、Serialize的两个重载方法

这两个方法的作用是使用Object转换为JSON字符串。Serialize(Object)方法会构造一个StringBuilder,再调用Serialize(Object, StringBuilder)方法得到结果,因此我们将目光对准后者。

其实Serialize方法的逻辑相对于Deserialize方法来说简单了不少,毕竟拼接字符串的工作一般总是比解析字符串的工作要容易。Serialize方法本身也是个递归方法,会递归地序列化一个对象的public属性和变量,因此在序列化一个复杂对象时往往会出现“循环引用”的状况,这时候就就会抛出异常。这时候JavaScriptConverter就起到其作用了,在序列化某个类型时,会查找serializer中是否有其对应的JavaScriptConveter,如果有的话,则会通过这个JavaScriptConverter得到一个IDictionary<string, object>,然后再为这个字典添加“__type”的值,最后再将这个字典对象序列化输出。需要注意的是,得到“__type”值的方式是通过JavaScriptConverter中的JavaScriptTypeResolver来得到类型的标识字符串。这个逻辑和反序列化操作正好相反。

这些就是ASP.NET AJAX服务器端提供的序列化与反序列化的能力。而且事实上它提供的扩展能力往往也已经足够了,这点着实为我们省去了许许多多的麻烦。

转载于:https://www.cnblogs.com/JeffreyZhao/archive/2006/11/10/Inside_Atlas_Series__Investigate_the_Serialization_and_Deserialization_Ability_2.html

深入Atlas系列:探究序列化与反序列化能力(下) - JavaScriptSerializer相关推荐

  1. Kafka消息序列化和反序列化(下)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  2. 深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息...

    如果要在客户端指定服务器端Web Service方法所接收的参数类型,就必须在客户端通过"__type"来指定,但是这就暴露了服务器端的具体类型了,这可不太好.现在我们就来看一下应 ...

  3. 深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持

    在上一篇文章中,我们讨论了使用ASP.NET AJAX默认的Profile Service.一般来说,它已经能够迎合大多数应用的需要了.不过除此之外,ASP.NET AJAX还提供了让我们自定义Pro ...

  4. ASP.NET中JSON的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  5. Kafka消息序列化和反序列化(上)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  6. 一起谈.NET技术,ASP.NET 中JSON 的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  7. php json字符串序列化,JSON序列化与反序列化实现方法(附代码)

    这次给大家带来JSON序列化与反序列化实现方法(附代码),JSON序列化与反序列化实现的注意事项有哪些,下面就是实战案例,一起来看一下. 一.JSON简介 JSON(JavaScript Object ...

  8. java序列化_夯实Java基础系列22:一文读懂Java序列化和反序列化

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. 夯实Java基础系列22:一文读懂Java序列化和反序列化

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

最新文章

  1. 【开篇】自我介绍和博客未来规划
  2. 【Java 泛型】泛型用法 ( 泛型编译期擦除 | 上界通配符 <? extends T> | 下界通配符 <? super T> )
  3. SAP收发存报表程序
  4. 七夕节,程序员们都怎么哄女朋友开心?
  5. 3.QT中QCommandLineParser和QCommandLineOption解析命令行参数
  6. centos7添加新网卡实现双IP双网关
  7. 飞畅科技-工业以太网交换机市场发展情况介绍
  8. LAMP平台下构建Postfix邮件服务器
  9. 威纶触摸屏使用说明书_MODBUS通信之触摸屏与变频器通信知识分享(一)
  10. 人工智能 - paddlepaddle飞桨 - 深度学习基础教程 - 语义角色标注
  11. oracle链接池满了怎么办,Oracle连接数满了
  12. linux界面唤醒,Linux计算机实现自动唤醒和关闭的方法步骤详解
  13. MFileServer管理员用户名密码配置
  14. 反射机制,从为什么讲起,更容易接受
  15. 小米笔记本 镜像_2020年小米笔记本Air 13.3原装WIN10出厂系统ISO镜像1607原版下载...
  16. 基于MATLAB的数字图像处理-图像进行灰度化
  17. Python实现多个Excel文件合并到一个文件中
  18. 条码防伪检测技术介绍,如何通过扫描商品条码判断产品的真伪-鸿顺捷条码防伪技术介绍
  19. 收发EtherCAT帧——ecx_recvpkt
  20. 微信定位精灵服务器或网络异常,微信定位精灵系统界面无法更新怎么办

热门文章

  1. c#连接数据库SqlHelper报错
  2. 字符串匹配【模板】(luogu 3375)
  3. Leetcode-204 Count Primes
  4. js添加广告模块,随页面移动而移动
  5. [ActionScript 3.0] 喷泉效果
  6. 建立分析模型和设计模型
  7. 下列服务使用的默认端口:ftp,ssh,telnet,dhcp,mail,pop3,smtp,dns,http,sm
  8. [Node.js] 模块化 -- path路径模块
  9. 进度条小飞机移动动画
  10. 7-8 字符串字母大小写转换 (15 分)