【.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\":\"[email protected]\"}";
            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命名空间

示例代码下载

时间: 2024-10-13 00:57:16

【.NET深呼吸】如何反序列化动态JSON的相关文章

序列化与反序列化之JSON

在不同编程语言之间传递对象,须把对象序列化为标准格式,比如XML 但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可被所有语言读取,也可方便地存储到磁盘或者通过网络传输 JSON不仅是标准格式,并且比XML更快,而且可直接在Web页面中读取,因为JSON表示的对象就是标准的JavaScript语言的对象 JSON和Python内置的数据类型对应如下: JSON类型 Python类型 {} dict [] list "string" str 1234.56 int或f

Python—序列化和反序列化模块(json、pickle和shelve)

什么是序列化 我们把对象(或者变量)从内存中变为可存储或者可传输的过程称为序列化.在python中为pickling,在其他语言中也被称之为serialization,marshalling,flattening等等.即序列化之后就可以将内存中的程序内容写入硬盘或者通过网络传输到其他机器上去.反序列化的过程则相反:将硬盘中的内容变为可以在内存中运行的程序的过程称为反序列化. Json模块 # encoding:utf-8 # 通过序列化和反序列化将内容存储到文件 import json json

反序列化Newtonsoft.Json.JsonReaderException:“Could not convert string to decimal: . Path &#39;SETTLEAMT&#39;, line 1, position 180.”

一个小小的问题 我居然纠结了小半天,我也是醉醉的了喔,天啊 到最后发现.....的问题,之前总感觉是我写法或者哪里的小细节的地方呢,我去  着急的我都想讲 脏话了,嗯 稳住  淑女 调试到这里的时候一直感觉 没有问题啊,哪里的问题...   然后  换了一下思路,代码 确实 没啥问题   要不把这个引用的Newtonsoft.json  更新一个版本试试   报着千个 不服的态度更新了,这个结果让我眼前一亮... 更新  更新 运行 测试程序     啊啊啊啊  不是我的问题  是版本 是版本

Python 中数据的序列化和反序列化(json处理)

概念: JSON(JavaScript Object Notation):是一种轻量级的数据交换格式. 易于人阅读和编写.同时也易于机器解析和生成. 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等). 这些

C# Winform反序列化复杂json字符串

最近接的私单是一个CS项目,里面所有的操作都是通过调用API接口来进行的. 接口详细说明 协议:https  请求方式:post  https://xx.xxx.net/app/clients 提交json 数据包 { "action":" food_t_list", "data":{ “pageIndex”:”1”, “pageSize”:”20”, “foodGId”:”1”, “storeId”:”1” } } 返回说明 正确时返回JSON

Memcached中对象反序列化和json字符串用jackson解析成对象的比较

如果项目已经发布,如果临时想对某个在Memcached中的key修改值,那么以对象形式存储的话,将很难修改,但如果以字符串形式存储,通过json解析成对象的话,则会方便很多,因为通过界面往Memcached 添加字符串值是很简单的. 现在来比较一下这两种方式在时间消耗方面的差异: package bean; import java.io.Serializable; public class User implements Serializable{ /** * 序列号 */ private st

python序列化与反序列化(json与pickle)

在python中,序列化可以理解为将python中对象的编码格式转换为json(pickle)格式的字符串,而反序列化可以 理解为将json(pickle)格式的字符串转换为python中对象的编码格式 举一个简单的例子,我们在vmvare环境下编写python程序,然后需要临时走开一下,但是我们又不想把这个vmvare关闭,这个时候我们可以选择挂机,这样我们再回来继续操作时候,就可以直接恢复到走之前的状态,那么我们之前编写的代码及vmvare的状态是保存在哪里了呢,实际上是保存在文件当中来了,

python序列化与反序列化(json、pickle)

1.什么是序列化&反序列化? 序列化:将字典.列表.类的实例对象等内容转换成一个字符串的过程. 反序列化:将一个字符串转换成字典.列表.类的实例对象等内容的过程 PS:Python中常见的数据结构可以统称为容器.序列(如列表和元组).映射(如字典)以及集合(set)是三类主要的容器. 场景一:我们在python中将一个功能给另外一段程序使用,怎么给? 方法一:功能存到文件,然后另一个python程序再从文件里读出来. 场景二:现在反过来怎么把读出来的文件字符串转换成字典? 方法二:eval()函

C# 后台通过网络地址访问百度地图取回当前在地图上的经纬度,并将取回的复杂Json格式字符串反序列化(Newtonsoft.Json)

直接上代码:解释都在代码中 ak 要自己去百度地图申请. 其中申请ak的时候,有个属性render直接填*就行. namespace HampWebControl 是我的空间命名! namespace HampWebControl 是我的空间命名! namespace HampWebControl 是我的空间命名! using Newtonsoft.Json; using System; using System.IO; using System.Net; using System.Securi