JSON.NET对象序列化示例教程

2023/7/6 10:13:35

json-net-logo JSON作为一种轻量级的数据交换格式,简单灵活,被很多系统用来数据交互,作为一名.NET开发人员,JSON.NET无疑是最好的序列化框架,支持XML和JSON序列化,高性能,免费开源,支持LINQ查询。目前已被微软集成于webapi框架之中,因此,熟练掌握JSON.NET相当重要,这篇文章是零度参考官网整理的示例,通过这些示例,可以全面了解JSON.NET提供的功能。

与其它任框架一样,要使用JSON.NET框架,首先需要在您的项目中引用它,框架可以点击这里到GITHUB开源社区下载,然后根据您项目的版本直接引用newtonsoft.json.dll即可,更快捷的方法是通过NUGET提供的包管理器来进行安装,安装方式如下所示。打开VisualStudio2013,单击〖工具〗,在〖NuGet程序包管理器〗菜单下选中〖程序包管理器控制台〗,在控制台输入以下命令后,回车即可自动安装最新版。

Install-Package Newtonsoft.Json

JSON.NET框架安装完成后,就可以在您的程序中使用它,下面就是零度提供的JSON.NET使用示例,其中绿色代码表示示例的输出结果,为了便于阅读,我们通过Formatting.Indented将代码格式化输出。

1、使用JSON.NET序列化对象

public class Account { public string Email { get; set; } public bool Active { get; set; } public DateTime CreatedDate { get; set; } public IList<string> Roles { get; set; } }

Account account = new Account { Email = "james@example.com", Active = true, CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc), Roles = new List<string> { "User", "Admin" } }; string json = JsonConvert.SerializeObject(account, Formatting.Indented); Console.WriteLine(json);

{ "Email": "james@example.com", "Active": true, "CreatedDate": "2013-01-20T00:00:00Z", "Roles": [ "User", "Admin" ] }

2、使用JSON.NET序列化List集合

List<string> videogames = new List<string> { "零度", "分享", "编程之美" }; string json = JsonConvert.SerializeObject(videogames); Console.WriteLine(json);

["零度","分享","编程之美"]

3、使用JSON.NET序列化dictionary字典

var 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 }

4、将序列化结果保存到指定的文件

public class Movie { public string Name { get; set; } public int Year { get; set; } }

Movie movie = new Movie { Name = "Bad Boys", Year = 1995 }; using (StreamWriter file = File.CreateText(@"e:\movie.json")) { JsonSerializer serializer = new JsonSerializer(); serializer.Serialize(file, movie); }

5、基于枚举类型的JsonConverters转换器

public enum StringComparison

List<StringComparison> stringComparisons = new List<StringComparison> { StringComparison.CurrentCulture, StringComparison.InvariantCulture }; string jsonWithoutConverter = JsonConvert.SerializeObject(stringComparisons); Console.WriteLine(jsonWithoutConverter);

[0,2]

string jsonWithConverter = JsonConvert.SerializeObject(stringComparisons, new StringEnumConverter()); Console.WriteLine(jsonWithConverter);

["CurrentCulture","InvariantCulture"]

var result = JsonConvert.DeserializeObject<List<StringComparison>>(jsonWithConverter, new StringEnumConverter()); Console.WriteLine(string.Join(", ", result.Select(c => c.ToString())));

CurrentCulture, InvariantCulture

6、通过JRaw将JS函数序列化到JSON中

public class JavaScriptSettings { public JRaw OnLoadFunction { get; set; } public JRaw OnUnloadFunction { get; set; } }

JavaScriptSettings settings = new JavaScriptSettings { OnLoadFunction = new JRaw("OnLoad"), OnUnloadFunction = new JRaw("function(e) { alert(e); }") }; string json = JsonConvert.SerializeObject(settings, Formatting.Indented); Console.WriteLine(json);

{ "OnLoadFunction": OnLoad, "OnUnloadFunction": function(e) { alert(e); } }

7、使用JSON.NET反序列化对象

public class Account { public string Email { get; set; } public bool Active { get; set; } public DateTime CreatedDate { get; set; } public IList<string> Roles { get; set; } }

string json = @"{ 'Email': 'james@example.com', 'Active': true, 'CreatedDate': '2013-01-20T00:00:00Z', 'Roles': [ 'User', 'Admin' ] }"; Account account = JsonConvert.DeserializeObject<Account>(json); Console.WriteLine(account.Email);

james@example.com

8、使用JSON.NET反序列化List集合

string json = @"['Starcraft','Halo','Legend of Zelda']"; List<string> videogames = JsonConvert.DeserializeObject<List<string>>(json); Console.WriteLine(string.Join(", ", videogames));

Starcraft, Halo, Legend of Zelda

9、使用JSON.NET反序列化dictionary字典

string json = @"{'href': 'www.xcode.me','target': '_blank'}"; var htmlAttributes = JsonConvert.DeserializeObject<Dictionary<string, string>>(json); Console.WriteLine(htmlAttributes["href"]);

www.xcode.me

10、序列化var匿名类型

有时候,我们并不需要先定义一个类,然后new一个对象后再进行序列化,JSON.NET支持匿名类型的序列化和反序列化。

var definition = new { Name = "零度编程", Site = "www.xcode.me" }; var json = JsonConvert.SerializeObject(definition); Console.WriteLine(json);

{ "Name": "零度编程", "Site": "www.xcode.me" }

var definition = new { Name = , Site = }; string json = @"{'Name':'零度编程','Site':'www.xcode.me'}"; var webSite = JsonConvert.DeserializeAnonymousType(json, definition); Console.WriteLine(webSite.Name);

零度编程

11、用新JSON字符串填充指定对象的属性值

Account account = new Account { Email = "james@example.com", Active = true, CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc), Roles = new List<string>{"User","Admin"} }; string json = @"{'Active': false, 'Roles': ['Expired']}"; JsonConvert.PopulateObject(json, account); Console.WriteLine(account.Active);

false

上面的示例中,account对象的Active值首次设置为true,可通过PopulateObject方法通过json字符串重新填充Active属性和Roles属性。

12、使用JSON.NET反序列化时可指定构造函数

首先我们定义如下的类型,我们希望JSON.NET反序列化对象时使用第2个构造函数,我们将第一个默认构造函数屏蔽,标记为私有private修饰符。第2个构造函数需要指定一个website对象作为参数,如果提供的参数为null则抛出异常:

public class Website { public string Url { get; set; } private Website() public Website(Website website) { if (website == null) throw new ArgumentNullException("website"); Url = website.Url; } }

现在使用一般的方式反序列化一个JSON字符串。

string json = @"{'Url':'http://www.xcode.me'}"; try { JsonConvert.DeserializeObject<Website>(json); } catch (Exception ex) { Console.WriteLine(ex); }

Value cannot be null.Parameter name: website

我们发现该序列化方法抛出了异常,并没有按照我们预想的方式进行反序列化,JSON.NET提供如下的方式指定公有构造函数。

Website website = JsonConvert.DeserializeObject<Website>(json, new JsonSerializerSettings { ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor }); Console.WriteLine(website.Url);

http://www.xcode.me

另外,JSON.NET提供了指定任何构造函数的JsonConstructorAttribute特性,只需要在构造函数上标记,即可指定构造函数。

public class User { public string UserName { get; private set; } public bool Enabled { get; private set; } public User() [JsonConstructor] public User(string userName, bool enabled) }

string json = @"{UserName: www.xcode.me,Enabled: true}"; User user = JsonConvert.DeserializeObject<User>(json); Console.WriteLine(user.UserName);

www.xcode.me

13、当对象的属性为默认值(0或null)时不序列化该属性

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 json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore }); Console.WriteLine(json);

14、反序列化时JSON属性与对象属性的数量必须一致

默认情况下,JSON.NET反序列化并不要求JSON属性的数量与对象属性的数量相等,也就是始终保持有则序列化,无则不序列化的原则,不会抛出异常。但是,我们的需求并非这样,我们希望属性数量不等或者未提供值时,抛出异常,而不是正常反序列化,可以这样。

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

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

</span><span style="color: blue;">try
</span><span style="color: black;">{
    </span><span style="color: #2b91af;">JsonConvert</span><span style="color: black;">.DeserializeObject<</span><span style="color: #2b91af;">Account</span><span style="color: black;">>(json, </span><span style="color: blue;">new </span><span style="color: #2b91af;">JsonSerializerSettings
    </span><span style="color: black;">{
        MissingMemberHandling = </span><span style="color: #2b91af;">MissingMemberHandling</span><span style="color: black;">.Error
    });
}
</span><span style="color: blue;">catch </span><span style="color: black;">(</span><span style="color: #2b91af;">JsonSerializationException </span><span style="color: black;">ex)
{
    </span><span style="color: #2b91af;">Console</span><span style="color: black;">.WriteLine(ex.Message);
}</span>

Could not find member 'DeletedDate' on object of type 'Account'. Path 'DeletedDate', line 4, position 23.

这样,当未全部指定对象的属性时,就会抛出异常,而不是部分属性序列化。

15、JSON.NET中忽略null值得处理器

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 json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Console.WriteLine(json);

{ "Name": "Nigal Newborn", "Age": 1 }

在上面的示例中,默认情况下JSON.NET会将对象的null属性值序列化为JSON中null值。当对象属性值为null时,可忽略序列化,只需要指定NullValueHandling即可,另外有一种场景是,当对象属性值为null时,需要替换为空字符串双引号,如何替换,请点击这里参阅零度的文章。

16、JSON.NET中循环引用的处理方法

有的对象具有循环引用,对象的属性是对象本身,这会导致JSON.NET进入无限死循环,我们需要指定ReferenceLoopHandling打破这种循环引用。

public class Employee { public string Name { get; set; } public Employee Manager { get; set; } }

Employee joe = new Employee { Name = "Joe User" }; Employee mike = new Employee { Name = "Mike Manager" }; joe.Manager = mike; mike.Manager = mike; string json = JsonConvert.SerializeObject(joe, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); Console.WriteLine(json);

{ "Name": "Joe User", "Manager": { "Name": "Mike Manager" } }

17、通过ContractResolver指定属性名首字母小写

通常,在.NET中属性采用PascalCase规则(首字母大写),在JavaScript中属性名使用CamelCase规则(首字母小写),我们希望序列化后的JSON字符串符合CamelCase规则,JSON.NET提供的ContractResolver可以设置属性名小写序列化,更灵活的设置请点击这里参阅零度的文章。

public class Person { public string FirstName { get; set; } public string LastName { get; set; }

    </span><span style="color: blue;">public string </span><span style="color: black;">FullName
    {
        </span><span style="color: blue;">get </span><span style="color: black;">{ </span><span style="color: blue;">return </span><span style="color: black;">FirstName + </span><span style="color: #a31515;">" " </span><span style="color: black;">+ LastName; }
    }
}</span>

Person person = new Person { FirstName = "Sarah", LastName = "Security" }; string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); Console.WriteLine(json);

{ "firstName": "Sarah", "lastName": "Security", "fullName": "Sarah Security" }

18、JSON.NET中通过特性序列化枚举类型

public enum UserStatus { NotConfirmed, Active, Deleted }

</span><span style="color: blue;">public class </span><span style="color: #2b91af;">User
</span><span style="color: black;">{
    </span><span style="color: blue;">public string </span><span style="color: black;">UserName { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }

    [</span><span style="color: #2b91af;">JsonConverter</span><span style="color: black;">(</span><span style="color: blue;">typeof</span><span style="color: black;">(</span><span style="color: #2b91af;">StringEnumConverter</span><span style="color: black;">))]
    </span><span style="color: blue;">public </span><span style="color: #2b91af;">UserStatus </span><span style="color: black;">Status { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

默认情况下JSON.NET针对枚举类型输出对应的INT值,如果需要输出具有语义的字符串,可指定JsonConverter的值为StringEnumConverter类型。

User user = new User { UserName = @"零度编程", Status = UserStatus.Deleted }; string json = JsonConvert.SerializeObject(user, Formatting.Indented); Console.WriteLine(json);

{ "UserName": "零度编程", "Status": "Deleted" }

19、指定需要序列化的属性

通过JsonProperty指定哪些字段应该被序列化,需要序列化则标记,不需要序列化则取消标记。

[JsonObject(MemberSerialization.OptIn)] public class File { //Id不需要序列化 public Guid Id { get; set; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">]
    </span><span style="color: blue;">public string </span><span style="color: black;">Name { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">]
    </span><span style="color: blue;">public int </span><span style="color: black;">Size { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

File file = new File { Id = Guid.NewGuid(), Name = "xcode.pdf", Size = 50 * 1024 }; string json = JsonConvert.SerializeObject(file, Formatting.Indented); Console.WriteLine(json);

{ "Name": "xcode.pdf", "Size": 51200 }

20、序列化对象时指定属性名

序列化对象时,可标记属性的JsonProperty特性,并指定需要序列化为JSON时应有的属性名。

public class Videogame { [JsonProperty("name")] public string Name { get; set; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">(</span><span style="color: #a31515;">"release_date"</span><span style="color: black;">)]
    </span><span style="color: blue;">public </span><span style="color: #2b91af;">DateTime </span><span style="color: black;">ReleaseDate { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

Videogame starcraft = new Videogame { Name = "Starcraft", ReleaseDate = new DateTime(1998, 1, 1) }; string json = JsonConvert.SerializeObject(starcraft, Formatting.Indented); Console.WriteLine(json);

{ "name": "Starcraft", "release_date": "1998-01-01T00:00:00" }

21、序列化时指定属性在JSON中的顺序

public class Person { [JsonProperty(Order = 2)] public string FirstName { get; set; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">(Order = 1)]
    </span><span style="color: blue;">public string </span><span style="color: black;">LastName { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

Person person = new Person { FirstName = "零度", LastName = "编程" }; string json = JsonConvert.SerializeObject(person, Formatting.Indented); Console.WriteLine(json);

{ "LastName": "编程", "FirstName": "零度" }

22、反序列化指定属性是否必须有值必须不为null

在反序列化一个JSON时,可通过JsonProperty特性的Required指定反序列化行为,当反序列化行为与指定的行为不匹配时,JSON.NET将抛出异常,Required是枚举,Required.Always表示属性必须有值切不能为null,Required.AllowNull表示属性必须有值,但允许为null值。

public class Videogame { [JsonProperty(Required = Required.Always)] public string Name { get; set; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">(Required = </span><span style="color: #2b91af;">Required</span><span style="color: black;">.AllowNull)]
    </span><span style="color: blue;">public </span><span style="color: #2b91af;">DateTime</span><span style="color: black;">? ReleaseDate { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

string json = @"{ 'Name': 'Starcraft III', 'ReleaseDate': null }"; Videogame starcraft = JsonConvert.DeserializeObject<Videogame>(json); Console.WriteLine(starcraft.Name);

Starcraft III

23、通过特性指定null值忽略序列化

public class Vessel { public string Name { get; set; } public string Class { get; set; }

    [</span><span style="color: #2b91af;">JsonProperty</span><span style="color: black;">(NullValueHandling = </span><span style="color: #2b91af;">NullValueHandling</span><span style="color: black;">.Ignore)]
    </span><span style="color: blue;">public </span><span style="color: #2b91af;">DateTime</span><span style="color: black;">? LaunchDate { </span><span style="color: blue;">get</span><span style="color: black;">; </span><span style="color: blue;">set</span><span style="color: black;">; }
}</span>

Vessel vessel = new Vessel { Name = "Red October", Class = "Typhoon" }; string json = JsonConvert.SerializeObject(vessel, Formatting.Indented); Console.WriteLine(json);

{ "Name": "Red October", "Class": "Typhoon" }

24、忽略不需要序列化的属性

并不是对象所有属性都要参与序列化,我们可以使用JsonIgnore特性排除不需要序列化的属性,下面示例中的PasswordHash将被忽略。

public class Account { public string FullName { get; set; } public string EmailAddress { get; set; } [JsonIgnore] public string PasswordHash { get; set; } }

Account account = new Account { FullName = "admin", EmailAddress = "admin@xcode.me", PasswordHash = "VHdlZXQgJ1FASmFtZXNOSw==" }; string json = JsonConvert.SerializeObject(account); Console.WriteLine(json);

{"FullName":"admin","EmailAddress":admin@xcode.me}

25、通过特性指定属性的默认序列化值

当属性没有赋值时,默认值一般是null或者0,我们可通过DefaultValue特性改变默认值,可用指定的字符替换,而不是输出null。

public class Customer { public string FirstName { get; set; } [DefaultValue("")] public string LastName { get; set; } }

{"FirstName":null,"LastName":""}

26、序列化或反序列化时指定日期时间格式

JSON.NET中提供一个名为JsonSerializerSettings的设置对象,可通过此对象设置很多序列化和反序列化的行为,如果要设置JSON.NET序列化输出的日期时间格式,只需要指定格式化字符串即可。默认序列化行为,日期时间格式如下:

public class Customer { public string FirstName { get; set; } public string LastName { get; set; } public DateTime CreateDate { get; set; } }

var custom = new Customer { FirstName = "零度", LastName = "编程", CreateDate = DateTime.Now }; string json = JsonConvert.SerializeObject(custom, Formatting.Indented); Console.WriteLine(json);

{ "FirstName": "零度", "LastName": "编程", "CreateDate": "2015-08-24T17:19:39.0227502+08:00" }

通过JsonSerializerSettings的DateFormatString属性指定日期时间格式:

JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; settings.Formatting = Formatting.Indented; string json = JsonConvert.SerializeObject(custom, settings); Console.WriteLine(json);

{ "FirstName": "零度", "LastName": "编程", "CreateDate": "2015-08-24 17:23:56" }

27、JSON字符串格式化

默认情况下通过JsonConvert.SerializeObject(object value)序列化后的JSON是压缩格式,为了便于阅读,通常需要将JSON字符串格式化处理。

var value = new Customer { FirstName = "零度", LastName = "编程"}; string json = JsonConvert.SerializeObject(value); Console.WriteLine(json);

{"FirstName":"零度","LastName":"编程"}

以上为指定格式化,将输出压缩版JSON字符串,可通过Formatting.Indented指定格式化输出。

string json = JsonConvert.SerializeObject(value, Formatting.Indented); Console.WriteLine(json);

{ "FirstName": "零度", "LastName": "编程" }

也可以指定JsonSerializerSettings对象的Formatting值为Formatting.Indented进行格式化,与上面的结果等效。

JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Formatting = Formatting.Indented; string json = JsonConvert.SerializeObject(value, settings); Console.WriteLine(json);

以上就是JSON.NET的序列化和反序列化示例,下一篇博客将总结JSON.NET与LINQ的结合,希望对您有所帮助。