C#中解析json文件有很多种方法,在多种方法中一般都会提到一个十分优秀的库:NewtonJson 。使用NewtonJson处理Json文件十分高效,而且在配置也十分简单,直接在Nuget包中导入即可。

目录

1.导入NewtonJson库

2.解析Json文件

2.1 最简单的序列化与反序列化

2.2 序列化集合和字典

2.3 反序列化集合和字典

2.4 将对象保存为Json文件&从文件解析为json

2.5 有条件的序列化对象成员

2.6 解析匿名类

2.7 将派生类解析为基类

2.8 防止重复写值

2.9 取消C#默认参数赋值& 过滤值为null的属性

2.10 类型缺少成员报错

3. 使用Linq处理json

3.1 解析Json的基本操作

3.2 修改Json(使用JObject)

3.3 合并Json文件

3.4 将Json类型转为普通类型

3.5 判断Json文件是否相等 &深度复制Json文件

4. 总结



1.导入NewtonJson库

编写C#程序肯定是在visual studio中写(暂不考虑unity等其他地方),那么无论你是在windows下还是Mac OS X下,visual studio都自带nuget包管理工具。本文以Mac OS X平台为例,首先新建一个项目叫ParseJson,然后在项目的依赖项中弹出快捷菜单,如下:

点击Nuget包管理,弹出一个窗口:

可以看到第一个就是我们想要的包,选中然后添加包即可。添加完成后在你的程序中添加下面两行:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

至此,基本配置就完成了。


2.解析Json文件

NewtonJson官网有详细的使用文档教程,有很多示例代码,这里就不过多介绍了,遇到不懂的问题可以去文档里面找资料。

2.1 最简单的序列化与反序列化

假设你在C#中有一个定义好的类,然后你生成了一个对象,想把这个对象保存为Json文件,你可以用SerializeObject()函数处理。看下面的代码:

using System;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;namespace ParseJson
{class Product{public string Name;public DateTime ExpiryDate;public Decimal Price;public String[] Sizes;}class Program{static void Main(string[] args){Product product = new Product(){Name = "Apple",ExpiryDate=new DateTime(2020,12,30),Price=2.99M,Sizes=new string[] {"small","medium","large"}};string output = JsonConvert.SerializeObject(product);//将Json文件以字符串的形式保存StreamWriter sw = new StreamWriter(@"/Users/qinyuanlong/Projects/SimpleTest/ParseJson/product.dat");sw.Write(output);sw.Close();Console.WriteLine(output);}}
}

这里我们创建了一个Product类,并且实例化了一个对象,利用JsonConvert.SerializeObject(product)将其转化为Json文件,并以字符串的形式存储在变量output,我们很容易将字符串保存到本地。可以查看保存到本地后的文件内容:

既然我们可以将对象以json文件的形式保存,自然我们也应该可以从Json格式恢复成对象,做法很简单,假设我们已经读取了本地文件Product.dat,并保存到了字符串变量output中,我们要从中恢复成Product对象只需一句话:

            //恢复对象Product p = JsonConvert.DeserializeObject<Product>(output);

值得一提的的是,当你的对象里面有集合对象时:

public class Acount
{public string Email {get;set;}public Ilist<string> Roles {get;set}
}

也可以直接使用上面的方法,转化为Json文件后,集合对象会以数组的形式存储。


2.2 序列化集合和字典

除了序列化自定义的类,还可以将C#中的集合对象序列化,这里我就不跑代码了,直接搬运官网的例子。

序列化字典:

List<string> videogames = new List<string>
{"Starcraft","Halo","Legend of Zelda"
};string json = JsonConvert.SerializeObject(videogames);Console.WriteLine(json);
// ["Starcraft","Halo","Legend of Zelda"]

List集合被转化为了数组,当然List里面可以是复杂的类型,如使用我们之前定义的Product:

            Product product1 = new Product(){Name = "Apple",ExpiryDate=new DateTime(2020,12,30),Price=2.99M,Sizes=new string[] {"small","medium","large"}};Product product2 = new Product(){Name = "cup",ExpiryDate = new DateTime(2099, 1, 1),Price = 9.99M,Sizes = new string[] { "s", "L", "M", "xL" }};List<Product> list = new List<Product>() { product1, product2 };string json = JsonConvert.SerializeObject(list);Console.WriteLine(json);

输出为:

[{"Name":"Apple","ExpiryDate":"2020-12-30T00:00:00","Price":2.99,"Sizes":["small","medium","large"]},{"Name":"cup","ExpiryDate":"2099-01-01T00:00:00","Price":9.99,"Sizes":["s","L","M","xL"]}]

序列化字典例子如下:

Dictionary<string, int> points = new Dictionary<string, int>
{{ "James", 9001 },{ "Jo", 3474 },{ "Jess", 11926 }
};string json = JsonConvert.SerializeObject(points, Formatting.Indented);Console.WriteLine(json);
// {
//   "James": 9001,
//   "Jo": 3474,
//   "Jess": 11926
// }

这里SerializeObject多了一个参数,Indented表示转化为的Json文件带缩进,这样输出会更加直观清晰。

2.3 反序列化集合和字典

反序列化和之前讲的类似,反序列化需要给出转化为对象的类型,反序列化集合:

string json = @"[{'Name': 'Product 1','ExpiryDate': '2000-12-29T00:00Z','Price': 99.95,'Sizes': null},{'Name': 'Product 2','ExpiryDate': '2009-07-31T00:00Z','Price': 12.50,'Sizes': null}
]";List<Product> products = JsonConvert.DeserializeObject<List<Product>>(json);Console.WriteLine(products.Count);
// 2Product p1 = products[0];Console.WriteLine(p1.Name);
// Product 1

反序列化集合一般转为List类型,如果你需要转化为其它类型,你可以后续再处理。反序列化字典也是如此:

string json = @"{""key1"":""value1"",""key2"":""value2""}";Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);Console.WriteLine(values.Count);
// 2Console.WriteLine(values["key1"]);
// value1

2.4 将对象保存为Json文件&从文件解析为json

在最开始的例子中,我们将对象先转为字符串,然后再写入一个dat文件中,事实上完全可以将文件保存为Json文件。有两种思路,一种还是先将json变为字符串,然后保存到自定义的json文件中

            Product product1 = new Product(){Name = "Apple",ExpiryDate=new DateTime(2020,12,30),Price=2.99M,Sizes=new string[] {"small","medium","large"}};Product product2 = new Product(){Name = "cup",ExpiryDate = new DateTime(2099, 1, 1),Price = 9.99M,Sizes = new string[] { "s", "L", "M", "xL" }};List<Product> list = new List<Product>() { product1, product2 };File.WriteAllText(@"/Users/qinyuanlong/Projects/SimpleTest/ParseJson/product1.json",JsonConvert.SerializeObject(list,Formatting.Indented));

我们用Vscode打开product1.json如下:

另一种方法是直接将对象转化为json文件:

            using(StreamWriterfile=File.CreateText(@"/Users/qinyuanlong/Projects/SimpleTest/ParseJson/product2.json")){JsonSerializer serializer = new JsonSerializer() { Formatting=Formatting.Indented};serializer.Serialize(file, list);}

得到的product2.json和前面是一样的。

从json文件中解析对象的操作几乎是一模一样的:只需要将SerializeObject函数换成DeserializeObject,WriteAllText换成ReadAllText,CreatText换成OpenText。

// read file into a string and deserialize JSON to a type
Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(@"c:\movie.json"));// deserialize JSON directly from a file
using (StreamReader file = File.OpenText(@"c:\movie.json"))
{JsonSerializer serializer = new JsonSerializer();Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
}

注意:直接从json转为对象,除了提供对象类型参数,还需要强制转化操作。


2.5 有条件的序列化对象成员

NewTonJson还支持有条件序列化对象,即对某些属性进行判断,如果不满足要求,则忽略该属性。

要实现部分属性的条件序列化,需要添加一些函数,这个函数和属性一一对应,函数名为:ShouldSerialize+属性名,函数的返回值为bool类型,当返回为True时,该属性将被序列化,为False则被忽略。看一个官方例子:

首先你有这样一个简单类:

public class Employee
{public string Name { get; set; }public Employee Manager { get; set; }public bool ShouldSerializeManager(){// don't serialize the Manager property if an employee is their own managerreturn (Manager != this);}
}

这里已经添加了Manager这个筛选函数,所以当Manage就是自己时,这个Manage会被忽略。

Employee joe = new Employee();
joe.Name = "Joe Employee";
Employee mike = new Employee();
mike.Name = "Mike Manager";joe.Manager = mike;// mike is his own manager
// ShouldSerialize will skip this property
mike.Manager = mike;string json = JsonConvert.SerializeObject(new[] { joe, mike }, Formatting.Indented);Console.WriteLine(json);
// [
//   {
//     "Name": "Joe Employee",
//     "Manager": {
//       "Name": "Mike Manager"
//     }
//   },
//   {
//     "Name": "Mike Manager"
//   }
// ]

不过一般而言,当数据量不是很大时,你可以有条件的使用Json文件的数据,也就是我不用这个属性,我就可以假设它不存在。

上面的例子固然可行,但是有个很麻烦的问题:你必须在设计类的时候就确定好条件序列化属性。

那么有没有更好的控制办法呢?答案是肯定的。

通过派生接口:IContractResolver,生产一个筛选对象可以实现定制化筛选,你不用在你的类里面添加函数。一般我们不用直接派生自IContractResolver,而是派生自它的一个派生类:

DefaultContractResolver

看下面这个例子,我们假设有这样一个图书类:

public class Book
{public string BookName { get; set; }public decimal BookPrice { get; set; }public string AuthorName { get; set; }public int AuthorAge { get; set; }public string AuthorCountry { get; set; }
}

我们想实现序列化以字母“A”开头或者“B”开头的属性,显然用之前的方法会很麻烦,我们用刚才的方法,派生一个筛选类:

public class DynamicContractResolver : DefaultContractResolver
{private readonly char _startingWithChar;public DynamicContractResolver(char startingWithChar){_startingWithChar = startingWithChar;}protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization){IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);// only serializer properties that start with the specified character//只需要在这里添加属性筛选properties =properties.Where(p => p.PropertyName.StartsWith(_startingWithChar.ToString())).ToList();return properties;}
}

这个类有一个成员变量:_startingWithChar,用来接受筛选参数;一个构造函数;一个筛选函数:CreateProperties,这个函数返回一个属性集合,函数首先获得类的所有属性,保存带properties中,然后你根据需求对properties进行处理。上面的函数实现了根据属性名的首字母进行筛选。所以我们就可以用这个类的对象作为参数去实现我们的需求:

Book book = new Book
{BookName = "The Gathering Storm",BookPrice = 16.19m,AuthorName = "Brandon Sanderson",AuthorAge = 34,AuthorCountry = "United States of America"
};string startingWithA = JsonConvert.SerializeObject(book, Formatting.Indented,new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('A') });// {
//   "AuthorName": "Brandon Sanderson",
//   "AuthorAge": 34,
//   "AuthorCountry": "United States of America"
// }string startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('B') });// {
//   "BookName": "The Gathering Storm",
//   "BookPrice": 16.19
// }

DefaultContractResolver中的CreateProperties是对多个属性筛选而言的,回到本节最开始的问题,我只想对Manage成员进行筛选,那么可以用CreateProperty这个函数,具体用法如下:

public class ShouldSerializeContractResolver : DefaultContractResolver
{public static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization){JsonProperty property = base.CreateProperty(member, memberSerialization);if (property.DeclaringType == typeof(Employee) && property.PropertyName == "Manager"){property.ShouldSerialize =instance =>{Employee e = (Employee)instance;return e.Manager != e;};}return property;}
}

这个的用法和前面类似,不过这里直接声明了一个类的静态成员,所以不需要new一个对象:

            string json = JsonConvert.SerializeObject(new[] { joe, mike }, Formatting.Indented,new JsonSerializerSettings { ContractResolver=ShouldSerializeContractResolver.Instance});

顺便要说明的是,为了成功运行需要添加新的命名空间:

using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

这里给出官网关于DefaultContrctResolver的链接。


2.6 解析匿名类

对于匿名类,由于序列化不需要给出对象类型,所以可以依然使用前面序列化自定义类的方法,但是反序列是需要提供类型的,那对于匿名类怎么办?,这个NewtonJson也替我们考虑了,例子如下:

var definition = new { Name = "" };string json1 = @"{'Name':'James'}";
var customer1 = JsonConvert.DeserializeAnonymousType(json1, definition);Console.WriteLine(customer1.Name);
// Jamesstring json2 = @"{'Name':'Mike'}";
var customer2 = JsonConvert.DeserializeAnonymousType(json2, definition);Console.WriteLine(customer2.Name);
// Mike

办法很简单,直接给一个匿名类的定义对象,传入参数即可。

2.7 将派生类解析为基类

将派生类解析为基类,需要一个派生自CustomeCreationConverter的对象,操作起来其实很简单,看一下官方的例子:

首先你有一个Person基类,然后派生了Employee类,并写好了派生自CustomeCreationConverter类的类PersonConverter:

public class Person
{public string FirstName { get; set; }public string LastName { get; set; }public DateTime BirthDate { get; set; }
}public class Employee : Person
{public string Department { get; set; }public string JobTitle { get; set; }
}public class PersonConverter : CustomCreationConverter<Person>
{public override Person Create(Type objectType){return new Employee();}
}

然后你想将Employee对象解析为Person,只需要传入一个PersonConvrter对象:

string json = @"{'Department': 'Furniture','JobTitle': 'Carpenter','FirstName': 'John','LastName': 'Joinery','BirthDate': '1983-02-02T00:00:00'
}";Person person = JsonConvert.DeserializeObject<Person>(json, new PersonConverter());Console.WriteLine(person.GetType().Name);
// EmployeeEmployee employee = (Employee)person;Console.WriteLine(employee.JobTitle);
// Carpenter

从结果可以看出,虽然是以Person解析的,但是实际上仍然是Employee类型。


2.8 防止重复写值

如果一个类的构造函数本身就对成员进行了赋值,那么在反序列化时,可能会调用一次构造函数容易造成重复写入,看下面的例子:

public class UserViewModel
{public string Name { get; set; }public IList<string> Offices { get; private set; }public UserViewModel(){Offices = new List<string>{"Auckland","Wellington","Christchurch"};}
}

构造函数对成员Offices进行了赋值:

string json = @"{'Name': 'James','Offices': ['Auckland','Wellington','Christchurch']
}";UserViewModel model1 = JsonConvert.DeserializeObject<UserViewModel>(json);foreach (string office in model1.Offices)
{Console.WriteLine(office);
}
// Auckland
// Wellington
// Christchurch
// Auckland
// Wellington
// ChristchurchUserViewModel model2 = JsonConvert.DeserializeObject<UserViewModel>(json, new JsonSerializerSettings
{ObjectCreationHandling = ObjectCreationHandling.Replace
});foreach (string office in model2.Offices)
{Console.WriteLine(office);
}
// Auckland
// Wellington
// Christchurch

如果不添加设定,Offices就是存在2遍初始值,为例避免这种情况,在反序列化的时候传入了一个setting对象,其ObejctCreationHandling属性为Replcae


2.9 取消C#默认参数赋值& 过滤值为null的属性

C#对于没有赋值的类型提供一个默认值,如Int类型默认值为0,string类型默认值为null,如果当一个对象的成员没有被赋值,我们希望得到的是一个空json,那么需要将setting的DefaultValueHandleling设置为Ignore。

public class Person
{public string Name { get; set; }public int Age { get; set; }public Person Partner { get; set; }public decimal? Salary { get; set; }
}Person person = new Person();string jsonIncludeDefaultValues = JsonConvert.SerializeObject(person, Formatting.Indented);Console.WriteLine(jsonIncludeDefaultValues);
// {
//   "Name": null,
//   "Age": 0,
//   "Partner": null,
//   "Salary": null
// }string jsonIgnoreDefaultValues = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
{DefaultValueHandling = DefaultValueHandling.Ignore
});Console.WriteLine(jsonIgnoreDefaultValues);
// {}

过滤值为null的成员只需要将NullValueHandling属性设置为Ignore。

public class Person
{public string Name { get; set; }public int Age { get; set; }public Person Partner { get; set; }public decimal? Salary { get; set; }
}Person person = new Person
{Name = "Nigal Newborn",Age = 1
};string jsonIncludeNullValues = JsonConvert.SerializeObject(person, Formatting.Indented);Console.WriteLine(jsonIncludeNullValues);
// {
//   "Name": "Nigal Newborn",
//   "Age": 1,
//   "Partner": null,
//   "Salary": null
// }string jsonIgnoreNullValues = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
{NullValueHandling = NullValueHandling.Ignore
});Console.WriteLine(jsonIgnoreNullValues);
// {
//   "Name": "Nigal Newborn",
//   "Age": 1
// }

2.10 类型缺少成员报错

当我们将下面的json文件:

string json = @"{'FullName': 'Dan Deleted','Deleted': true,'DeletedDate': '2013-01-20T00:00:00'
}";

解析为Account类型时:

public class Account
{public string FullName { get; set; }public bool Deleted { get; set; }
}

是可以成功的,因为json中包含Accout类中所有成员属性。但是如果我们要严格转化(特别是在Accout漏掉属性时),需要报错,那么就需要设置setting的MissingMemberHandling属性。

try
{JsonConvert.DeserializeObject<Account>(json, new JsonSerializerSettings{MissingMemberHandling = MissingMemberHandling.Error});
}
catch (JsonSerializationException ex)
{Console.WriteLine(ex.Message);// Could not find member 'DeletedDate' on object of type 'Account'. Path 'DeletedDate', line 4, position 23.
}

此外还有很多设置用来解决各种问题,上面只是列出了一些常见的,有需要的还是要去官网查看。


3. 使用Linq处理json

使用ling处理json最大的好处是摆脱了对象的束缚,使用NewtonJson自带的一套体系。我们都知道JavaScript原生支持Json,直接可以将Json文件转化为一个对象,JObject的创建也是为了实现这样一个类似的功能。

3.1 解析Json的基本操作

  • 解析文本为Json对象
    直接使用JObject.Parse(obj)即可

    string json = @"{CPU: 'Intel',Drives: ['DVD read/writer','500 gigabyte hard drive']
    }";JObject o = JObject.Parse(json);
    Console.WriteLine(o.ToString());
    // {
    //   "CPU": "Intel",
    //   "Drives": [
    //     "DVD read/writer",
    //     "500 gigabyte hard drive"
    //   ]
    // }
  • 将数组解析为Json
    直接使用JArray类

    string json = @"['Small','Medium','Large'
    ]";JArray a = JArray.Parse(json);Console.WriteLine(a.Tostring());
    // [
    //   "Small",
    //   "Medium",
    //   "Large"
    // ]
  • 从本地Json文件中解析 
    读操作

    using (StreamReader reader = File.OpenText(@"c:\person.json"))
    {JObject o = (JObject)JToken.ReadFrom(new JsonTextReader(reader));// do stuff
    }

    写操作

    JObject videogameRatings = new JObject(new JProperty("Halo", 9),new JProperty("Starcraft", 9),new JProperty("Call of Duty", 7.5));File.WriteAllText(@"c:\videogames.json", videogameRatings.ToString());// write JSON directly to a file
    using (StreamWriter file = File.CreateText(@"c:\videogames.json"))
    using (JsonTextWriter writer = new JsonTextWriter(file))
    {videogameRatings.WriteTo(writer);
    }
  • 创建JObject对象,JArray对象
    JArray array = new JArray();
    array.Add("Manual text");
    array.Add(new DateTime(2000, 5, 23));JObject o = new JObject();
    o["MyArray"] = array;string json = o.ToString();
    // {
    //   "MyArray": [
    //     "Manual text",
    //     "2000-05-23T00:00:00"
    //   ]
    // }
  • 使用C#中的集合初始化语法创建复杂对象
    可以直接使用C#的初始化语法创建嵌套类型

    JObject o = new JObject
    {{ "Cpu", "Intel" },{ "Memory", 32 },{"Drives", new JArray{"DVD","SSD"}}
    };Console.WriteLine(o.ToString());
    // {
    //   "Cpu": "Intel",
    //   "Memory": 32,
    //   "Drives": [
    //     "DVD",
    //     "SSD"
    //   ]
    // }

    当然也可以用传统的对象创建方法,但是会觉得繁琐,看下面的例子:

    public class Post
    {public string Title { get; set; }public string Description { get; set; }public string Link { get; set; }public IList<string> Categories { get; set; }
    }
    List<Post> posts = GetPosts();JObject rss =new JObject(new JProperty("channel",new JObject(new JProperty("title", "James Newton-King"),new JProperty("link", "http://james.newtonking.com"),new JProperty("description", "James Newton-King's blog."),new JProperty("item",new JArray(from p in postsorderby p.Titleselect new JObject(new JProperty("title", p.Title),new JProperty("description", p.Description),new JProperty("link", p.Link),new JProperty("category",new JArray(from c in p.Categoriesselect new JValue(c)))))))));Console.WriteLine(rss.ToString());// {
    //   "channel": {
    //     "title": "James Newton-King",
    //     "link": "http://james.newtonking.com",
    //     "description": "James Newton-King's blog.",
    //     "item": [
    //       {
    //         "title": "Json.NET 1.3 + New license + Now on CodePlex",
    //         "description": "Announcing the release of Json.NET 1.3, the MIT license and being available on CodePlex",
    //         "link": "http://james.newtonking.com/projects/json-net.aspx",
    //         "category": [
    //           "Json.NET",
    //           "CodePlex"
    //         ]
    //       },
    //       {
    //         "title": "LINQ to JSON beta",
    //         "description": "Announcing LINQ to JSON",
    //         "link": "http://james.newtonking.com/projects/json-net.aspx",
    //         "category": [
    //           "Json.NET",
    //           "LINQ"
    //         ]
    //       }
    //     ]
    //   }
    // }
  • 动态创建JObject和JArray对象
    使用C#的动态类型,可以动态的创建JObject和JArray对象

    dynamic product = new JObject();
    product.ProductName = "Elbow Grease";
    product.Enabled = true;
    product.Price = 4.90m;
    product.StockCount = 9000;
    product.StockValue = 44100;
    product.Tags = new JArray("Real", "OnSale");Console.WriteLine(product.ToString());
    // {
    //   "ProductName": "Elbow Grease",
    //   "Enabled": true,
    //   "Price": 4.90,
    //   "StockCount": 9000,
    //   "StockValue": 44100,
    //   "Tags": [
    //     "Real",
    //     "OnSale"
    //   ]
    // }
  • 使用JTokenWriter动态创建JObject对象
    JTokenWriter类有一套完整的节点写入方法,详细文档在此,在写入的过程,有点像在JS中添加Dom元素。

    JTokenWriter writer = new JTokenWriter();
    writer.WriteStartObject();
    writer.WritePropertyName("name1");
    writer.WriteValue("value1");
    writer.WritePropertyName("name2");
    writer.WriteStartArray();
    writer.WriteValue(1);
    writer.WriteValue(2);
    writer.WriteEndArray();
    writer.WriteEndObject();JObject o = (JObject)writer.Token;Console.WriteLine(o.ToString());
    // {
    //   "name1": "value1",
    //   "name2": [
    //     1,
    //     2
    //   ]
    // }
  • 从自定义对象生成JObject对象 
    使用FromObject函数可以从自定义的类中生产JObject对象,用法如下:

    public class Computer
    {public string Cpu { get; set; }public int Memory { get; set; }public IList<string> Drives { get; set; }
    }JValue i = (JValue)JToken.FromObject(12345);Console.WriteLine(i.Type);
    // Integer
    Console.WriteLine(i.ToString());
    // 12345JValue s = (JValue)JToken.FromObject("A string");Console.WriteLine(s.Type);
    // String
    Console.WriteLine(s.ToString());
    // A stringComputer computer = new Computer
    {Cpu = "Intel",Memory = 32,Drives = new List<string>{"DVD","SSD"}
    };JObject o = (JObject)JToken.FromObject(computer);Console.WriteLine(o.ToString());
    // {
    //   "Cpu": "Intel",
    //   "Memory": 32,
    //   "Drives": [
    //     "DVD",
    //     "SSD"
    //   ]
    // }JArray a = (JArray)JToken.FromObject(computer.Drives);Console.WriteLine(a.ToString());
    // [
    //   "DVD",
    //   "SSD"
    // ]

    这个函数还可以直接从匿名对象创建:

    List<Post> posts = new List<Post>
    {new Post{Title = "Episode VII",Description = "Episode VII production",Categories = new List<string>{"episode-vii","movie"},Link = "episode-vii-production.aspx"}
    };JObject o = JObject.FromObject(new
    {channel = new{title = "Star Wars",link = "http://www.starwars.com",description = "Star Wars blog.",item =from p in postsorderby p.Titleselect new{title = p.Title,description = p.Description,link = p.Link,category = p.Categories}}
    });Console.WriteLine(o.ToString());
    // {
    //   "channel": {
    //     "title": "Star Wars",
    //     "link": "http://www.starwars.com",
    //     "description": "Star Wars blog.",
    //     "item": [
    //       {
    //         "title": "Episode VII",
    //         "description": "Episode VII production",
    //         "link": "episode-vii-production.aspx",
    //         "category": [
    //           "episode-vii",
    //           "movie"
    //         ]
    //       }
    //     ]
    //   }
    // }

从JObject恢复出类对象
这个实际上没有什么技巧,只是写一个动态创建函数:

public class BlogPost
{public string Title { get; set; }public string AuthorName { get; set; }public string AuthorTwitter { get; set; }public string Body { get; set; }public DateTime PostedDate { get; set; }
}
string json = @"[{'Title': 'Json.NET is awesome!','Author': {'Name': 'James Newton-King','Twitter': '@JamesNK','Picture': '/jamesnk.png'},'Date': '2013-01-23T19:30:00','BodyHtml': '&lt;h3&gt;Title!&lt;/h3&gt;\r\n&lt;p&gt;Content!&lt;/p&gt;'}
]";JArray blogPostArray = JArray.Parse(json);IList<BlogPost> blogPosts = blogPostArray.Select(p => new BlogPost
{Title = (string)p["Title"],AuthorName = (string)p["Author"]["Name"],AuthorTwitter = (string)p["Author"]["Twitter"],PostedDate = (DateTime)p["Date"],Body = HttpUtility.HtmlDecode((string)p["BodyHtml"])
}).ToList();Console.WriteLine(blogPosts[0].Body);
// <h3>Title!</h3>
// <p>Content!</p>

那么反过来,也可以用这个方法将对象变为Jobject对象:

IList<BlogPost> blogPosts = new List<BlogPost>
{new BlogPost{Title = "Json.NET is awesome!",AuthorName = "James Newton-King",AuthorTwitter = "JamesNK",PostedDate = new DateTime(2013, 1, 23, 19, 30, 0),Body = @"<h3>Title!</h3><p>Content!</p>"}
};JArray blogPostsArray = new JArray(blogPosts.Select(p => new JObject{{ "Title", p.Title },{"Author", new JObject{{ "Name", p.AuthorName },{ "Twitter", p.AuthorTwitter }}},{ "Date", p.PostedDate },{ "BodyHtml", HttpUtility.HtmlEncode(p.Body) },}));Console.WriteLine(blogPostsArray.ToString());
// [
//   {
//     "Title": "Json.NET is awesome!",
//     "Author": {
//       "Name": "James Newton-King",
//       "Twitter": "JamesNK"
//     },
//     "Date": "2013-01-23T19:30:00",
//     "BodyHtml": "&lt;h3&gt;Title!&lt;/h3&gt;&lt;p&gt;Content!&lt;/p&gt;"
//   }
// ]

3.2 修改Json(使用JObject)

JObject对象很容易修改Json文件,修改包括增,删,重写,等操作。

string json = @"{'channel': {'title': 'Star Wars','link': 'http://www.starwars.com','description': 'Star Wars blog.','obsolete': 'Obsolete value','item': []}
}";JObject rss = JObject.Parse(json);JObject channel = (JObject)rss["channel"];channel["title"] = ((string)channel["title"]).ToUpper();
channel["description"] = ((string)channel["description"]).ToUpper();channel.Property("obsolete").Remove();channel.Property("description").AddAfterSelf(new JProperty("new", "New value"));JArray item = (JArray)channel["item"];
item.Add("Item 1");
item.Add("Item 2");Console.WriteLine(rss.ToString());
// {
//   "channel": {
//     "title": "STAR WARS",
//     "link": "http://www.starwars.com",
//     "description": "STAR WARS BLOG.",
//     "new": "New value",
//     "item": [
//       "Item 1",
//       "Item 2"
//     ]
//   }
// }

在上面的例子,依次进行了:使用函数修改值,删除属性,在某属性后面添加属性,在数组内部添加成员。


3.3 合并Json文件

合并Json文件也很简单,类似于两个集合的操作,看下面的例子:

JObject o1 = JObject.Parse(@"{'FirstName': 'John','LastName': 'Smith','Enabled': false,'Roles': [ 'User' ]
}");
JObject o2 = JObject.Parse(@"{'Enabled': true,'Roles': [ 'User', 'Admin' ]
}");o1.Merge(o2, new JsonMergeSettings
{// union array values together to avoid duplicatesMergeArrayHandling = MergeArrayHandling.Union
});string json = o1.ToString();
// {
//   "FirstName": "John",
//   "LastName": "Smith",
//   "Enabled": true,
//   "Roles": [
//     "User",
//     "Admin"
//   ]
// }

这里要说的是,可以使用MergeArrayHandling对象来设置合并方式,上面使用的是合并模式:Union,即当前Json有时,只会出现一次,此外还有:

类似与数学中的并集,补集,叠加。

此外,MergeNullValueHandling属性可以控制在合并是值为Null的要不要被忽略;


3.4 将Json类型转为普通类型

JObject对象中的成员类型并不是C#中类型,要变成普通类型,你需要使用:ToObject<T>() 做最后一步转换,其中T为你想转换为的类型,不进行转换直接打印可能会报错。

JValue v1 = new JValue(true);bool b = v1.ToObject<bool>();Console.WriteLine(b);
// trueint i = v1.ToObject<int>();Console.WriteLine(i);
// 1string s = v1.ToObject<string>();Console.WriteLine(s);
// "True"

虽然很简单,但是刚接触NewtonJson可能会遇到这个问题。


3.5 判断Json文件是否相等 &深度复制Json文件

使用JToken.DeepEquals函数判断两个JObject对象是否相等,这个相等必须要所有属性值一模一样:

JValue s1 = new JValue("A string");
JValue s2 = new JValue("A string");
JValue s3 = new JValue("A STRING");Console.WriteLine(JToken.DeepEquals(s1, s2));
// trueConsole.WriteLine(JToken.DeepEquals(s2, s3));
// falseJObject o1 = new JObject
{{ "Integer", 12345 },{ "String", "A string" },{ "Items", new JArray(1, 2) }
};JObject o2 = new JObject
{{ "Integer", 12345 },{ "String", "A string" },{ "Items", new JArray(1, 2) }
};Console.WriteLine(JToken.DeepEquals(o1, o2));
// trueConsole.WriteLine(JToken.DeepEquals(s1, o1["String"]));
// true

注意:虽然两个json问价的内容一样,但是它们毕竟是2个不同的对象,使用JToken.RefernceEquals判断会返回false。

对于拷贝,主要是对内容进行拷贝,但是创建的是新对象:

JValue s1 = new JValue("A string");
JValue s2 = new JValue("A string");
JValue s3 = new JValue("A STRING");Console.WriteLine(JToken.DeepEquals(s1, s2));
// trueConsole.WriteLine(JToken.DeepEquals(s2, s3));
// falseJObject o1 = new JObject
{{ "Integer", 12345 },{ "String", "A string" },{ "Items", new JArray(1, 2) }
};JObject o2 = new JObject
{{ "Integer", 12345 },{ "String", "A string" },{ "Items", new JArray(1, 2) }
};Console.WriteLine(JToken.DeepEquals(o1, o2));
// trueConsole.WriteLine(JToken.DeepEquals(s1, o1["String"]));
// true

4. 总结

以上就是对NewtonJson的一点总结,很多是参考官方文档,我只选了一些常见的知识点进行介绍,建议大家遇到不能解决的问题时还是看官方文档。

一般而言,我更倾向与使用JObject对象处理Json,因为你可以获得JavaScript处理Json的90%的体验,使用起来很灵活,而且结合Linq语法,可以很方便的处理它。

C# 解析Json文件(使用NewtonJson库)相关推荐

  1. Java性能优化:正确的解析JSON文件

    为什么80%的码农都做不了架构师?>>>    数据收集服务平均1小时OOM(java.lang.OutOfMemoryError: GC overhead limit exceed ...

  2. 使用C/C++解析json文件

    目录 为什么? 怎么做? 为什么? 举个例子,我们在使用C/C++进行深度学习模型的测试,由于测试过程中可能有许多参数要传给model,比如在进行目标检测时,要传入nms阈值等.我们要最优化测试结果, ...

  3. java解析json文件_Java性能优化:正确的解析JSON文件

    数据收集服务平均1小时OOM(java.lang.OutOfMemoryError: GC overhead limit exceeded)一次,发现都是在下载处理 JSON Atom Feed时OO ...

  4. 关于 pandas 解析 json 文件和其他类型文件的结果中日期格式数据类型不一致的问题

    问题: 我有两个文件,一个 .csv 文件和一个 .json 文件,数据截图分别如下: 我的目的是解析这些文件,并将结果统一交由下一个程序块进行处理. 在了解到 pandas 可以解析数据文件(csv ...

  5. C++解析json文件

    文章目录 1 JSON文件简介[1] 1.1 JSON文件的语法规则 1.2 JSON值的类型 2 JSON文件解析 1 JSON文件简介[1] 一个项目在设计时会存在很多参数,比如data文件路径. ...

  6. python解析json_python解析json文件

    概念 序列化(Serialization):将对象的状态信息转换为可以存储或可以通过网络传输的过程,传输的格式可以是JSON.XML等.反序列化就是从存储区域(JSON,XML)读取反序列化对象的状态 ...

  7. 如何使用PHP解析JSON文件? [重复]

    本文翻译自:How can I parse a JSON file with PHP? [duplicate] This question already has an answer here: 这个 ...

  8. Python解析json文件

    Python解析json文件 实现代码 import json import sysstdout = sys.stdoutwith open("company.json", &qu ...

  9. 解析json文件、执行批量修改sql

    要求:解析json文件,取出其中的参数,修改数据库中的数据 数据量:190万条 使用线程池批量处理sql 1.线程: public class DateHandleThread extends Thr ...

  10. 解析json文件的Go依赖包

    上一篇golang读取json配置文件介绍了使用encoding/json包来解析json文件,但是这种方法在面对结构复杂.字段较多的情况时,解析效率不是很高.上一篇中,我们在解析json文件时,需要 ...

最新文章

  1. 2021年大数据Spark(七):应用架构基本了解
  2. 左室短轴切面_4声窗7切面搞定急诊超声心动图:由浅入深学TTE急诊“心”事
  3. 第十一课.DCGAN与CycleGAN
  4. 基于USR-WiFi模块的 ESP32,ESP8266 Thonny调试器
  5. mysql自动提交的概念_MySQL入门之事务概念
  6. 向量距离计算 java_在机器学习中扮演着极为重要角色的向量
  7. [Java] 蓝桥杯ADV-176 算法提高 陶陶摘苹果
  8. 镜头对摄像机性能的影响
  9. 蓝桥杯新增web应用开发科目—送给想要参赛的小伙伴们一份备赛指南
  10. 基本的http压力测试工具
  11. 激光条纹中心提取——zhang细化+灰度重心法
  12. TCP连接异常终止(RST包)场景分析
  13. 外卖订餐系统的设计与实现/点餐订餐系统
  14. oracle默认导出dmp路径_Oracle导入导出dmp文件
  15. Vue+SpringBoot+ElementUI实战学生管理系统-10.学生管理模块
  16. 乐融致新不再纳入乐视网合并报表范围 融创已是最大股东
  17. 用计算机唱歌 丑八怪乐谱,丑八怪歌曲谱子_丑八怪简谱
  18. opencv图片矩形网格边线_图像算法在数值计算中的应用(1):Canny边缘检测算法...
  19. 湖南计算机专业好的二本学校排名2015,2015湖南二本大学排名
  20. Thinkphp+layui数据表格实现表格分页

热门文章

  1. Excel 地址 行列转换
  2. makefile 目标:依赖文件写法
  3. 华为应用市场AGC研习社直播:App个人信息安全保护审核标准解读
  4. 【脚本】Python+adb王者荣耀闯关自动刷金币
  5. 根据ip查询真实地址
  6. 演讲实录 :某大型股份制商业银行的容器化探索之路
  7. 自然语言处理—文本分类综述/什么是文本分类
  8. 快速文本分类(FastText)
  9. 英文缩写400个速查
  10. 手机企业邮箱客户端哪个好用?