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

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

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

本着“第三方包一定有比系统自带类优秀地方,否则就不会存在”的原则,再加上 JavaScriptSerializerDataContractJsonSerializer 等这些自带类库使用起来很麻烦,我毫不犹豫地就选择了在 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 = ,
Name = "Jim David",
Scores = new double[] { 87.5, , 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 = ,
Name = "Jim David",
Scores = new double[] { 87.5, , 76.2 }
};
Student student2 = new Student
{
Id = ,
Name = "Milly Smith",
Scores = new double[] { 92.5, , 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);
//
Student s = studentsList[];
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);
//
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> 对象(用于迭代访问列表中的每一个对象),最后再依次反序列化列表中的对象。

C#使用Json.NET解析Json的更多相关文章

  1. JSON.stringify()方法是将一个javascript值(对象或者数组)转换成为一个JSON字符串;JSON.parse()解析JSON字符串,构造由字符串描述的javascript值或对象

    JSON.stringify()方法是将一个javascript值(对象或者数组)转换成为一个JSON字符串:JSON.parse()解析JSON字符串,构造由字符串描述的javascript值或对象

  2. Python | JSON 数据解析(Json & JsonPath)

    一.什么是JSON? JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.它基于 ECMAScript (欧洲计算机协会制定的js规范)的一 ...

  3. Python3基础 json.loads 解析json格式的数据,得到一个字典

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  4. JSON.parse 解析json字符串时,遇换行符报错

    Json字符串转换成Json对象时候,有两种方式: 假设d是json字符串: 1,eval('(' + d + ')'). 2,JSON.parse(d): 但是以上方式有隐患,如果Json字符串有换 ...

  5. Android原生生成JSON与解析JSON

    JSON数据是一种轻量级的数据交换格式,在Android中通常应用于client与server交互之间的传输数据.像如今在网上有非常多解析JSON数据的jar包,可是归根究竟用的都是Android原生 ...

  6. scala解析json —— json4s 解析json方法汇总

    使用json4s的框架,包括spark,flink 1.org.json4s 引入pom的方法 对于本地支持,引入以下依赖项添加到pom中 <dependency> <groupId ...

  7. JSON.parse 解析json字符串时,遇字符串换行符,解析失败

    今天遇到json字符串转对象时报错了,发现有个字符串有换行符,仔细找了原因. 结果是因为JSON.parse转json字符串时遇到一些特殊字符需要先转义,如图所示 然后尝试了各路大神介绍的办法,均不适 ...

  8. GO语言练习:构建json 和 解析JSON 实例

    本文介绍如何使用Go语言自带的库把对象转换为JSON格式,并在channel中进行传输后,并把JSON格式的信息转换回对象. 1.Go语言的JSON 库 Go语言自带的JSON转换库为 encodin ...

  9. Newtonsoft.Json.dll解析json的dll文件使用

    要解析的json //解析前 //解析前 {,,,,,,,,,,},,,,,,,,,,,},,,,,,,,,,,,,,,,},,,,,,,,,},,,,,,,,,,,,},,,,,,,,,,,},,, ...

随机推荐

  1. 第二篇 dom内容操作之value

    一.内容操作的三种方式 . 详情看第一篇 innerText innerHtml . value ==>表单类的标签 input >text passwd textarea . check ...

  2. while & do-while

    while的形式——while(条件表达式){循环体:} 当满足条件表达式时,执行循环体,之后继续验证是否满足条件表达式,满足继续执行循环体,之后重复,直到不满足条件表达式,循环结束.    先判断, ...

  3. O(1) 快速乘

    有一些毒瘤题,数据大小不光会炸\(int\),有时甚至会炸\(long long\).这时一个\(O(1)\)的防爆乘就很重要了 \(a*b%p\)可以转化为\(a*b-[a*b/p]*p\) 这里用 ...

  4. 《python基础教程(第二版)》学习笔记 语句/循环/条件(第5章)

    <python基础教程(第二版)>学习笔记 语句/循环/条件(第5章) print 'AB', 123 ==> AB 123 # 插入了一个空格print 'AB', 'CD' == ...

  5. OTSU大津法对图像二值化

    OTSU算法 (1)原理: 对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于背景的像素个数占整幅图像的比例记为ω0,其平均灰度μ0:前景像素个数占整幅图像的比例为ω1,其平均灰度为μ1 ...

  6. jQuery-选择器(2)

    jQuery选择器(2) 继续学习jquery选择器,感受它对于操作DOM节点的方便. [属性筛选选择器]属性选择器可以让你基于属性来定位一个元素.可以只指定该元素的某属性,这样所有使用该属性而不管它 ...

  7. Geoserver端口冲突解决方案(二)

    转载:https://blog.csdn.net/sx341125/article/details/52091903 上一篇文章说了GeoServer的安装问题,其中一个问题就是GeoServer端口 ...

  8. freeMarker(十三)——XML处理指南之揭示XML文档

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 前言 尽管 FreeMarker 最初被设计用作Web页面的模板引擎, ...

  9. 表达式计算-----------eval()运算符

    1.java的eval()方法(或称之为运算符)可以将字符串解析成可以运行的javaScript代码,例如 eval()只有一个参数.如果传入的参数不是一个字符串,那么它会直接返回这个参数.如果传入的 ...

  10. centos6.6系统初始化脚本

    #!/bin/bash # Program: # system_init_shell # History: # 2012/06/01 25061008@qq.com # Release: # 1.1 ...