C#使用Json.NET解析Json

本文转载自 http://xiaosheng.me/2016/10/01/article25/

最近在 C# 项目中需要使用到 Json 格式的数据,我简单上网搜索了一下,基本上有两种操作 Json 数据的方法:

  • 使用 Windows 系统自带的类
  • 使用第三方的包

本着“第三方包一定有比系统自带类优秀地方,否则就不会存在”的原则,再加上 JavaScriptSerializer、DataContractJsonSerializer 等这些自带类库使用起来很麻烦,我毫不犹豫地就选择了在 Json 操作方面小有名气的 Json.NET。Json.NET 自己也做了与自带类库的比较,详情可以见 Json.NET vs .NET Serializers 和 Json.NET vs Windows.Data.Json。

Json.NET 是一个 Newtonsoft 编写的开源类库包,你可以直接到 Github 上查看项目的源码和说明。Json.NET 提供了大量对于 Json 数据的操作方法,他们使用起来非常简单,而且执行效率很高。

.NET 对象的序列化和反序列化

1. 普通对象的序列化和反序列化

JsonConvert 是 Json.NET 中的一个数据转换类,提供了用于 .NET 对象序列化和反序列化的方法 SerializeObject() 和 DeserializeObject()。在通常情况下,我们也只需要使用这两个方法就足以完成任务了。

比如说,我们现在定义了一个学生类 Student:

class Student //学生类
{public int Id { get; set;} //学号public string Name { get; set;} //姓名public double[] Scores { get; set;} //成绩
}

现在我们创建一个学生类对象,并使用 JsonConvert 类提供的 SerializeObject() 方法将它转换到 Json 字符串(需要引入命名空间 using Newtonsoft.Json):

Student student = new Student
{Id = 12883,Name = "Jim David",Scores = new double[] { 87.5, 92, 76.2 }
};string jsonStudent = JsonConvert.SerializeObject(student);
//{"Id":12883,"Name":"Jim David","Scores":[87.5,92.0,76.2]}

可以看到在序列化的过程中,JsonConvert 会将 .NET 对象中的变量名转换为 Json 中的“属性”,同时将变量的值复制为 Json 的“属性值”。接下来,我们尝试将 Json 字符串转换为 Student 对象,使用 JsonConvert 提供的 DeserializeObject() 方法:

Student deserializedStudent = JsonConvert.DeserializeObject<Student>(jsonStudent);
Console.WriteLine("student.Id = " + deserializedStudent.Id);
//student.Id = 12883
Console.WriteLine("student.Name = " + deserializedStudent.Name);
//student.Name = Jim David

可以看到,创建的学生对象 student 的 Json 字符串被顺利地解析成了 Student 对象。在调用 DeserializeObject() 方法进行反序列化时,最好使用带泛型参数的重载方法。

如果在调用 DeserializeObject() 时不指定对象类型,JsonConvert 会默认转换为 Object 对象。

集合的序列化和反序列化

上面我们已经简单测试了 JsonConvert 提供的 SerializeObject() 和 DeserializeObject() 方法,完成了 .NET 对象的序列化和反序列化。

C# 项目中,除了自定义的类型外,集合(Collections)也是经常会使用的数据类型,包括列表、数组、字典或者我们自定义的集合类型。我们同样可以使用之前使用的 SerializeObject() 和 DeserializeObject() 方法来完成集合的序列化和反序列化。

为了使转换后的结果更加易读,我指定转换后的 Json 字符串带缩进。通过向 SerializeObject() 方法传递进第二个参数 Formatting 实现。
Student student1 = new Student
{Id = 12883,Name = "Jim David",Scores = new double[] { 87.5, 92, 76.2 }
};
Student student2 = new Student
{Id = 35228,Name = "Milly Smith",Scores = new double[] { 92.5, 88, 85.7 }
};
List<Student> students = new List<Student>();
students.Add(student1);
students.Add(student2);
string jsonStudents = JsonConvert.SerializeObject(students, Formatting.Indented);
//[
//  {
//    "Id": 12883,
//    "Name": "Jim David",
//    "Scores": [
//      87.5,
//      92.0,
//      76.2
//    ]
//  },
//  {
//    "Id": 35228,
//    "Name": "Milly Smith",
//    "Scores": [
//      92.5,
//      88.0,
//      85.7
//    ]
//  }
//]

接下来我们对上面生成的 Json 字符串进行反序列化,解析出原有的 Student 类型列表。同样,我们需要使用带泛型参数的 DeserializeObject() 方法,指定 JsonConvert 解析的目标类型。

string jsonStudentList = @"[{'Id': 12883,'Name': 'Jim David','Scores': [87.5,92.0,76.2]},{'Id': 35228,'Name': 'Milly Smith','Scores': [92.5,88.0,85.7]}
]";List<Student> studentsList = JsonConvert.DeserializeObject<List<Student>>(jsonStudentList);
Console.WriteLine(studentsList.Count);
//2
Student s = studentsList[0];
Console.WriteLine(s.Name);
//Jim David

如果 Json 对象拥有统一类型的属性和属性值,我们还可以把 Json 字符串反序列化为 .NET 中的字典,Json 对象的“属性”和“属性值”会依次赋值给字典中的 Key 和 Value。下面我举一个简单的例子:

string json = @"{""English"":88.2,""Math"":96.9}";
Dictionary<string, double> values = JsonConvert.DeserializeObject<Dictionary<string, double>>(json);
Console.WriteLine(values.Count);
//2
Console.WriteLine(values["Math"]);
//96.9

解析复杂的 Json 字符串

如今大量的 Web API 为我们编写复杂程序提供了极大的方便,例如百度地图 API、图灵机器人 API等等,利用这些 Web 应用程序我们可以充分发挥云服务的优势,开发出大量有趣的应用。

Web API 通常返回 Json 或 XML 格式的检索数据,由于 Json 数据量更小,所以目前大多数情况下我们都选择返回 Json 格式的数据。

如果返回的 Json 文档很大,而我们仅仅需要其中的一小部分数据。按照之前的方法,我们必须首先定义一个与 Json 对象对应的 .NET 对象,然后反序列化,最后才能从对象中取出我们需要的数据。而有了 Json.NET,这个任务就很容易实现了,我们可以局部地解析一个 Json 对象。

下面以获取 Google 搜索结果为例,简单演示一下对复杂结构 Json 文档的解析。

string googleSearchText = @"{'responseData': {'results': [{'GsearchResultClass': 'GwebSearch','unescapedUrl': 'http://en.wikipedia.org/wiki/Paris_Hilton','url': 'http://en.wikipedia.org/wiki/Paris_Hilton','visibleUrl': 'en.wikipedia.org','cacheUrl': 'http://www.google.com/search?q=cache:TwrPfhd22hYJ:en.wikipedia.org','title': '<b>Paris Hilton</b> - Wikipedia, the free encyclopedia','titleNoFormatting': 'Paris Hilton - Wikipedia, the free encyclopedia','content': '[1] In 2006, she released her debut album...'},{'GsearchResultClass': 'GwebSearch','unescapedUrl': 'http://www.imdb.com/name/nm0385296/','url': 'http://www.imdb.com/name/nm0385296/','visibleUrl': 'www.imdb.com','cacheUrl': 'http://www.google.com/search?q=cache:1i34KkqnsooJ:www.imdb.com','title': '<b>Paris Hilton</b>','titleNoFormatting': 'Paris Hilton','content': 'Self: Zoolander. Socialite <b>Paris Hilton</b>...'}],'cursor': {'pages': [{'start': '0','label': 1},{'start': '4','label': 2},{'start': '8','label': 3},{'start': '12','label': 4}],'estimatedResultCount': '59600000','currentPageIndex': 0,'moreResultsUrl': 'http://www.google.com/search?oe=utf8&ie=utf8...'}},'responseDetails': null,'responseStatus': 200
}";

上面就是从 Google 搜索返回的 Json 数据,我们现在需要的是 responseData 属性下的 results 列表中结果,而且仅仅需要结果中的 titlecontent 和 url 属性值。

public class SearchResult
{public string Title { get; set; }public string Content { get; set; }public string Url { get; set; }
}
//将 Json 文档解析为 JObject
JObject googleSearch = JObject.Parse(googleSearchText);
//将获得的 Json 结果转换为列表
IList<JToken> results = googleSearch["responseData"]["results"].Children().ToList();
//将 Json 结果反序列化为 .NET 对象
IList<SearchResult> searchResults = new List<SearchResult>();
foreach(JToken result in results)
{SearchResult searchResult = JsonConvert.DeserializeObject<SearchResult>(result.ToString());searchResults.Add(searchResult);
}
// Title = <b>Paris Hilton</b> - Wikipedia, the free encyclopedia
// Content = [1] In 2006, she released her debut album...
// Url = http://en.wikipedia.org/wiki/Paris_Hilton// Title = <b>Paris Hilton</b>
// Content = Self: Zoolander. Socialite <b>Paris Hilton</b>...
// Url = http://www.imdb.com/name/nm0385296/

可以看到,对 Json 文档的解析基本分为以下几步:

  1. 将 Json 文档转换为 JObject 对象
  2. 使用JObject[属性]获取 JObject 对象中某个属性的值(JToken 格式)
    可以继续通过 JToken[属性] 获取属性内部的属性值(依然为 JToken 格式)
  3. 将 JToken 格式的属性值反序列化为 .NET 对象

如果属性值为我们需要的数据对象,那么直接反序列化该对象就可以了;如果属性值为列表(比如上面 results 属性的值),那么就可以调用 JToken 类的 Children() 函数,获得一个可迭代的 JEnumerable<JToken> 对象(用于迭代访问列表中的每一个对象),最后再依次反序列化列表中的对象。

 

转载于:https://www.cnblogs.com/wphl-27/p/8358025.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

现在JavaScript日期–如何在JavaScript中获取当前日期

Many applications you build will have some sort of a date component, whether its the creation date of a resource, or the timestamp of an activity. 您构建的许多应用程序都将具有某种日期组件&#xff0c;无论是资源的创建日期还是活动的时间戳。 Dealing with date…

233. 数字 1 的个数

给定一个整数 n&#xff0c;计算所有小于等于 n 的非负整数中数字 1 出现的个数。 示例 1&#xff1a; 输入&#xff1a;n 13 输出&#xff1a;6 示例 2&#xff1a; 输入&#xff1a;n 0 输出&#xff1a;0 解题思路 正确性证明 例如&#xff1a;对于n3015&#xff0c…

Linux串口设置参数

为什么80%的码农都做不了架构师&#xff1f;>>> 在Linux环境下&#xff0c;串口名从ttyS0开始依次是ttyS1、ttyS2等。在本程序中&#xff0c;使用ttyS0作为通信串口。在打开ttyS0的时候选项 O_NOCTTY 表示不能把本串口当成控制终端&#xff0c;否则用户的键盘输入信…

STM32F013 十元板

我大拇指般大小。STM32F103C8T6&#xff0c;64K Flash&#xff0c;20K RAM&#xff0c;m3的核。十元&#xff0c;应该是价格极限了吧。 通过USB供电&#xff08;5V&#xff09;&#xff0c;也可以排针3.3V供电。可惜没有引出5V排针。USB口可以供电和USB通讯&#xff0c;没有USB…

如何在Python中建立和训练K最近邻和K-Means集群ML模型

One of machine learnings most popular applications is in solving classification problems.机器学习最流行的应用之一是解决分类问题。 Classification problems are situations where you have a data set, and you want to classify observations from that data set in…

552. 学生出勤记录 II

552. 学生出勤记录 II 可以用字符串表示一个学生的出勤记录&#xff0c;其中的每个字符用来标记当天的出勤情况&#xff08;缺勤、迟到、到场&#xff09;。记录中只含下面三种字符&#xff1a; ‘A’&#xff1a;Absent&#xff0c;缺勤 ‘L’&#xff1a;Late&#xff0c;迟…

C/C++中计算函数运行时间

#include<stdio.h> #include<time.h> clock_t start,stop;//clock_t 是clock&#xff08;&#xff09;函数返回变量的类型 double duration;//记录被测函数的运行时间&#xff0c;以秒为单位 int main() { startclock();//开始计时 MyFunction();//把被测函数加在这…

作为一名前端开发工程师,你必须掌握的WEB模板引擎:Handlebars

为什么需要使用模板引擎&#xff1f; 关于为什么要使用模板引擎&#xff0c;按照我常说的一句话就是&#xff1a;不用重复造轮子了。 简单来说&#xff0c;模板最本质的作用是“变静为动”&#xff0c;一切利于这方面的都是优势&#xff0c;不利于的都是劣势。要想很好地实现“…

extjs 实用开发指南_如何提出有效问题:针对开发人员的实用指南

extjs 实用开发指南Learning is a journey that never ends. At every point in your career, you will keep learning, re-learning, and un-learning. 学习是一个永无止境的旅程。 在职业生涯的每个阶段&#xff0c;您都会不断学习&#xff0c;重新学习和不学习。 The abil…

LOJ 6270

最近&#xff08;一直&#xff09;有点&#xff08;很&#xff09;蠢 按照区间大小排序做区间包含多少区间的话 只用考虑 左端点比当前左端点小的和右端点比当前右端点大的&#xff0c;因为不可能同时满足 关于K&#xff0c;就在做到K的时候减一下就好了&#xff0c;一直傻逼在…

Zabbix3.4安装详细步骤

Zabbix3.4安装的详细步骤一、zabbix介绍现在大多数公司都会用到监控软件&#xff0c;主流的监控软件就是Zabbix了&#xff0c;当然还会有Nagios等其他的软件&#xff1a;zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix能监视各种…

软件自学成才到公司要学历吗_作为一名自学成才的移动开发人员,我在旅途中学到了什么

软件自学成才到公司要学历吗In this post, Ill share my entire journey about how I became a professional mobile developer.在这篇文章中&#xff0c;我将分享我如何成为一名专业的移动开发人员的整个过程。 I hope that reading about my experience will help you refle…

cs231n---语义分割 物体定位 物体检测 物体分割

1 语义分割 语义分割是对图像中每个像素作分类&#xff0c;不区分物体&#xff0c;只关心像素。如下&#xff1a; &#xff08;1&#xff09;完全的卷积网络架构 处理语义分割问题可以使用下面的模型&#xff1a; 其中我们经过多个卷积层处理&#xff0c;最终输出体的维度是C*H…

http协议内容

前言&#xff1a; http协议&#xff1a; 对浏览器客户端 和 服务器端 之间数据传输的格式规范http1.0&#xff1a;当前浏览器客户端与服务器端建立连接之后&#xff0c; 只能发送一次请求&#xff0c;一次请求之后连接关闭。 http1.1&#xff1a;当前浏览器客户端与服务器端建…

array_combine()

转载于:https://www.cnblogs.com/xiaobiaomei/p/8392728.html

CSS外边距(margin)重叠及防止方法

#css外边距margin重叠及防止方法CSS外边距(margin)重叠及防止方法 #1-什么是外边距margin重叠1. 什么是外边距(margin)重叠 外边距重叠是指两个或多个盒子(可能相邻也可能嵌套)的相邻边界(其间没有任何非空内容、补白、边框)重合在一起而形成一个单一边界。 #2-相邻marign重叠的…

composer windows安装

一.前期准备: 1.下载安装包,https://getcomposer.org/download/ 2.在php.ini文档中打开extensionphp_openssl.dll 3.下载php_ssh2.dll、php_ssh2.pdb,http://windows.php.net/downloads/pecl/releases/ssh2/0.12/ 4.把php_ssh2.dll、php_ssh2.pdb文件放php的ext文件夹 5.重启ap…

spring整合mybatis采坑

本来这个错误是整合spring和mybatis遇到的错误&#xff0c;但是一直没有解决&#xff0c;但是在做SpringMVC时也了出现了这样的错误org.springframework.beans.factory.BeanCreationException: Error creating bean with name sqlSessionFactory defined in class path resourc…

处理测试环境硬盘爆满

测试环境经常会收到这类告警 第一步 登陆机器查看硬盘使用 执行df 好吧,使用情况真不妙,根目录占用过大 第二步 确定哪个文件太大或者文件过多 进入爆满的目录,如这里是根目录 cd / 然后找下面哪个文件夹或者文件太大,有几种方式: 1.dusudo du -h --max-depth1 | sort -hr 越前…

LeetCode-46. Permutations

一、问题描述 就是全排列问题。 二、问题解决 应该哪一本数据结构的书上都有讲了。 void get_permute(vector<int>& nums, int pos, vector<vector<int>>& result) {if (nums.size() pos) {result.push_back(nums);return;}for (int i pos; i <…