【.NET深呼吸】如何反序列化动态JSON
.net本身除了支持SOAP、XML、二进制等序列化和反序列化,后来也加入了对JSON的序列化的支持。然而,在实际开发中,常常会遇到结构不确定的JSON对象,这些对象可能是其他代码动态生成的,你事先无法估计它的结构,甚至它的字段名字是动态改变的。
这种情况下,我们很难用一个固定的类来进行反序列化,后来我尝试过从DynamicObject类派生出一个自定义的动态类型,希望通过这种方法能够将动态生成的JSON读出来,但结果依旧不可;后来我又实现了ISerializable接口,想着自行去控制一下数据的读取,但仍然未果。
最终我总结出来,只有下面这个方法比较省事,并且可以做到将动态的JSON进行反序列化。
做ASP.NET开发的朋友应该会熟悉一个类——位于System.Web.Script.Serialization命名空间下的JavaScriptSerializer类。因为这个类是为Web开发服务的,其实可以用于整个.net框架,即你在WinForm、WPF等程序中依旧可以用。这个类的作用是将指定的JSON字符串进行序列化和反序列化,参与操作的类型可以是固定的,如果JSON是固定结构的,这样就可行。而对于结构不固定的JSON,这个类可以以字典的形式进行操作,即调用DeserializeObject方法后会返回一个Object类型的对象,实际上这个对象是实现了IDictionary<string, object>接口的,这样一来,反序列化的结果就可以作为字典来操作。如果JSON里面有嵌套的对象,则返回的字典对象中会嵌套着字典对象。
于是,我就写了这么一个类:
public sealed class JsonObjectReader
{
private string innerJson = null;
public JsonObjectReader(string json)
{
innerJson = json;
} public dynamic GetObject()
{
dynamic d = new ExpandoObject();
// 将JSON字符串反序列化
JavaScriptSerializer s = new JavaScriptSerializer();
object resobj = s.DeserializeObject(this.innerJson);
// 拷贝数据
IDictionary<string, object> dic = (IDictionary<string, object>)resobj;
IDictionary<string, object> dicdyn = (IDictionary<string, object>)d;
foreach (var item in dic)
{
dicdyn.Add(item.Key, item.Value);
}
return d;
}
}
有人会问我,GetObject方法为什么要返回动态类型?是为了方便操作,ExpandoObject是一种简单易用并且现成的动态类型,在C#中声明变量时应用上dynamic关键字,告诉编译器这家伙是动态类型,在编译检查时可以“网开一面”。而且,我发现ExpandoObject类是显式实现了IDictionary<string, object>接口的,说明你还可以把它强制转换为字典数据来操作。
这种做法一举两得,如果方便使用,就当成动态对象来访问,在不方便使用时,也可以当作字典数据来用。
下面举一个不方便使用动态访问的例子:
string json = "{" +
"\"0592\" : \"厦门市\"," +
"\"0351\" : \"太原市\"," +
"\"0411\" : \"大连市\"," +
"\"0459\" : \"大庆市\"" +
"}";
JsonObjectReader rd = new JsonObjectReader(json);
dynamic res = rd.GetObject();
IDictionary<string, object> d = (IDictionary<string, object>)res;
foreach (var item in d)
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
大伙会发现,这个JSON你是很难用常规方法进行反序列化的,因为它的字段是城市的区号,是不固定的,在声明类时你无法事先确定类的属性或字段成员。同时你也发现,字段名是数字的,就算以动态对象得到结果,你也不能以obj.0459这样的语法来访问,因为标识符是不能由数字开头的。这种情况下不能用动态对象来访问,但可以把它转换为字典对象来处理。
得到结果如下图。

但是,下面这种用法,因为JSON的字段名不是数字开头,所以能够以动态对象的方式访问。
json = "{\"Name\":\"小明\", \"Age\":25, \"Email\":\"abcd@dog.cc\"}";
JsonObjectReader rd2 = new JsonObjectReader(json);
dynamic res2 = rd2.GetObject();
Console.WriteLine($"姓名:{res2.Name}");
Console.WriteLine($"年龄:{res2.Age}");
Console.WriteLine($"电邮:{res2.Email}");
因为Name、Age、Email这些字段不是数字开头,符号标识符的规范要求,所以后面可以用res2.Name的方式来访问,就像访问普通对象实例一样。
得到的结果如下图。

最后要说明一下的是,这种方法只用于.NET框架的应用程序,如ASP.NET、WPF等。如果是Windows Store App的话,可以使用RT API中的JSON相关的类来处理,这些类都位于Windows.Data.Json命名空间。
【.NET深呼吸】如何反序列化动态JSON的更多相关文章
- 动态Json字符串的解析
动态Json字符串的解析 对于传统的Json字符串,比如有规定属性的对象,通常都会采用反序列化的方式就可以了,例如下面的方式: DataContractJsonSerializer ser = new ...
- Java对象序列化与反序列化一 JSON
Java对象序列化与反序列化一 JSON 1. 依赖库 jackson-all-1.6.1.jar 2. 代码 public class Student { private String nam ...
- 『动态』动态JSON万能转换函数 + .Net40 dynamic动态数据绑定
不废话,调用代码: static void Main(string[] args) { string json = File.ReadAllText("2.txt", Encodi ...
- 序列化与反序列化之JSON
在不同编程语言之间传递对象,须把对象序列化为标准格式,比如XML 但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可被所有语言读取,也可方便地存储到磁盘或者通过网络传输 JSON不 ...
- 序列化与反序列化,json,pickle,xml,shelve,configparser模块
序列化与反序列化 什么是序列化?序列化就是将内存中的数据结构转换成一种中间格式存储到硬盘或者基于网络传输.反序列化就是将硬盘中或者网络中传来的一种数据格式转换成内存中数据结构. 为什么要有? 1.可以 ...
- Python—序列化和反序列化模块(json、pickle和shelve)
什么是序列化 我们把对象(或者变量)从内存中变为可存储或者可传输的过程称为序列化.在python中为pickling,在其他语言中也被称之为serialization,marshalling,flat ...
- C#动态实体集的反序列化(动态JSON反序列化)
一.使用场景 我们在将 JSON 反序列化实体集的时候,如果字段是固定的,那么我们序列化非常简单,对应字段写的实体集就可以了.比如下面这种: { "data":[ { " ...
- C#序列化和反序列化 之 dynamic 动态Json的反序列化
序列化和反序列化的常识不再赘述,如果不清楚这个,可以 参考一下其他人写的文章https://www.cnblogs.com/maitian-lf/p/3670570.html 总结的说, 序列化 是把 ...
- C# JToken类的使用,实现解析动态json数据、遍历、查找
在原来解析json数据是,一般都是用反序列化来实现json数据的解读,这需要首先知道json数据的结构并且建立相应的类才能反序列化,一旦遇到动态的json数据,这种方法就不使用. 为了解决动态解析js ...
随机推荐
- 消息队列 Kafka 的基本知识及 .NET Core 客户端
前言 最新项目中要用到消息队列来做消息的传输,之所以选着 Kafka 是因为要配合其他 java 项目中,所以就对 Kafka 了解了一下,也算是做个笔记吧. 本篇不谈论 Kafka 和其他的一些消息 ...
- .Net中的AOP系列之构建一个汽车租赁应用
返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...
- C#文件安全管理解析
在实际的项目开发中,我们经常需要使用到文件的I/O操作,主要包含对文件的增改删查等操作,这些基本的操作我们都是很熟悉,但是较少的人去考虑文件的安全和操作的管理等方面,例如文件的访问权限管理,文件数据的 ...
- Web安全相关(三):开放重定向(Open Redirection)
简介 那些通过请求(如查询字符串和表单数据)指定重定向URL的Web程序可能会被篡改,而把用户重定向到外部的恶意URL.这种篡改就被称为开发重定向攻击. 场景分析 假设有一个正规网站http:// ...
- 负载均衡——nginx理论
nginx是什么? nginx是一个强大的web服务器软件,用于处理高并发的http请求和作为反向代理服务器做负载均衡.具有高性能.轻量级.内存消耗少,强大的负载均衡能力等优势. nginx架构? ...
- 基于Vue2.0的单页面开发方案
2016的最后一天,多多少少都应该总结一下这一年的得失,哪里做的好,哪里需要改进,记一笔,或许将来会用到呢. 毕业差不多半年了,一直是一个人在负责公司项目的前端开发与维护,当时公司希望前后端分离,提高 ...
- 初识git版本控制系统
当下git分布式版本控制系统越来越火,掌握git也是必须的一个技能.因此,对git做了如下学习. Git初级指南 1. 先安装git.(ps:在select cmponents处要勾选Git Bash ...
- SymmetricDS 快速和灵活的数据库复制
开始谈谈开源的SymmetricDS,谈谈实际使用中,遇到的一些问题和解决办法.持续更新: SymmetricDS 快速和灵活的数据库复制 实际使用 和 埋过的坑 (一)知识篇 SymmetricDS ...
- 我的MYSQL学习心得(十一) 视图
我的MYSQL学习心得(十一) 视图 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
- CentOS 7 上部署Mono 4 和Jexus 5.6
概述 在这篇文章中我们将讨论如何在CentOS 7操作系统,安装 jexus. mono 和 配置 jexus,因此它将能够在这种环境中运行一个asp.net mvc 4 应用.这篇文章是描述如何在 ...