目录
1.1.4、ObjectCreationHandling设置
2.1、默认模式[JsonObject(MemberSerialization.OptIn/OptOut)]
2.2、序列化为集合JsonArrayAttribute/JsonDictionaryAttribute
2.6、将意外元素存到集合JsonExtensionData
引言
Newtonsoft.Json是一款高性能Json序列化和解析工具,开源免费!它使得配置文件的保存和读取变得简单,提供对类属性和字段的序列化控制,以及在序列化过程中或完成后执行相应的方法。
1、简单使用
1.1、官方案例
序列化:
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product,Formatting.Indented);//格式化Formatting.Indented
// {
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
// }
1.1.1、TypeNameHandling设置
序列化和反序列化时添加JsonSerializerSettings,属性TypeNameHandling设置为TypeNameHandling.All。作用:就是设置Json.NET能够序列化接口或继承类的关键,将TypeNameHandling设置为All后,Json.NET会在序列化后的json文本中附加一个属性说明json到底是从什么类序列化过来的,也可以设置TypeNameHandling为Auto,表示让Json.NET自动判断是否需要在序列化后的json中添加类型属性,如果序列化的对象类型和声明类型不一样的话Json.NET就会在json中添加类型属性,反之就不添加。
这在抽象类中,不同子类组成的列表中非常有用。对于抽象类Person,继承类:Student、Employee,组成列表List<Person>,反序列化时如果不标记,会报无法创建抽象类实例或接口的错误。这就需要标记其类型。
string str = JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
1.1.2、NullValueHandling设置
对于空值是否序列化,Ignore:则忽略,默认不忽略,记为如:Age:null。
1.1.3、Formatting设置
Formatting.Indented 文本中自动换行并缩进,可读性更好。默认不格式化。
1.1.4、ObjectCreationHandling设置
控制当使用Jsonconvert.PopulateObject反序列化时,将字符串反序列化到一个现有实例上应该做怎样的操作。
Auto:会以附加的方式添加列表元素,属性直接替换。
Replace:直接替换,不附加。
反序列化:
string json = @"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys
LINQ to Json:
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"
// ]
// }
1.2、JsonConvert
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "ExpiryDate": "2008-12-28T00:00:00",
// "Price": 3.99,
// "Sizes": [
// "Small",
// "Medium",
// "Large"
// ]
//}
Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);
最常用的反序列化方法:
| DeserializeObject<T>(String) | Deserializes the JSON to the specified .NET type. |
| DeserializeObject<T>(String,JsonConverter[]) | Deserializes the JSON to the specified .NET type using a collection of JsonConverter. |
| DeserializeObject<T>(String, JsonSerializerSettings) | Deserializes the JSON to the specified .NET type using JsonSerializerSettings. |
2、特性
2.1、默认模式[JsonObject(MemberSerialization.OptIn/OptOut)]
[JsonObject(MemberSerialization.OptIn)]:默认不序列化,成员必须具有 JsonProperty 或 DataMember 属性才能序列化
[JsonObject(MemberSerialization.OptOut)]:默认都序列化,添加[JsonIgnore]的忽略。
不加特性系统默认是都序列化。
//默认不序列化,添加特性的序列化
[JsonObject(MemberSerialization.OptIn)]
public class Person
{
// "John Smith"
[JsonProperty]
public string Name { get; set; }
// "2000-12-15T22:11:03"
[JsonProperty]
public DateTime BirthDate { get; set; }
// new Date(976918263055)
[JsonProperty]
public DateTime LastModified { get; set; }
// not serialized because mode is opt-in
public string Department { get; set; }
}
[JsonObject(MemberSerialization.OptOut)]
public class Person
{
// "John Smith"
public string Name { get; set; }
// "2000-12-15T22:11:03"
public DateTime BirthDate { get; set; }
// new Date(976918263055)
public DateTime LastModified { get; set; }
// not serialized
[JsonIgnore]
public string Department { get; set; }
}
2.2、序列化为集合JsonArrayAttribute/JsonDictionaryAttribute
JsonArrayAttribute 和 JsonDictionaryAttribute 用于指定是否将一个类序列化为该集合类型。
集合属性有多个选项,可自定义应用于集合项的 JsonConverter、类型名称处理和引用处理。
2.3、序列化该元素JsonProperty
JsonPropertyAttribute 有多种用途:
默认情况下,JSON 属性的名称与 .NET 属性的名称相同。该属性允许自定义名称。
当成员序列化设置为选择加入时,JsonPropertyAttribute 表示应序列化属性。
它包括序列化和反序列化中的非公共属性。
它可用于自定义属性值的类型名称、引用、空值和默认值处理。
可用于自定义序列化属性名称的命名策略。
可用于自定义属性的 JsonConverter 集合项、类型名称处理和引用处理。
DataMemberAttribute 可用于替代 JsonPropertyAttribute。
public class Myclass
{
[JsonProperty("数值")]
public int number;
}
{"数值":0}
2.4、忽略元素JsonIgnoreAttribute
JsonIgnoreAttribute 忽略属性
将字段或属性排除在序列化之外。
NonSerializedAttribute 可用于替代 JsonIgnoreAttribute。
2.5、序列化方式JsonConverter
JsonConverterAttribute 属性指定了用于转换对象的 JsonConverter。
该属性可以放在类上,也可以放在成员上。如果将该属性放在类上,该属性指定的 JsonConverter 将是该类序列化的默认方式。当属性位于字段或属性上时,指定的 JsonConverter 将始终用于序列化该值。
使用哪个 JsonConverter 的优先级是成员属性,然后是类属性,最后是传递给 JsonSerializer 的任何转换器。
public enum UserStatus
{
NotConfirmed,
Active,
Deleted
}
public class User
{
public string UserName { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public UserStatus Status { get; set; }
}
{"UserName":null,"Status":"NotConfirmed"}
而不是
{"UserName":null,"Status":0}
本例显示了 JsonConverterAttribute 应用于一个属性的情况。
要将 JsonConverter 应用于集合中的项,可使用 JsonArrayAttribute、JsonDictionaryAttribute 或 JsonPropertyAttribute,并将 ItemConverterType 属性设置为要使用的转换器类型。
2.6、将意外元素存到集合JsonExtensionData
JsonExtensionDataAttribute 会指示 JsonSerializer 将类型中没有匹配字段或属性的属性反序列化到指定的集合中。在序列化过程中,该集合中的值会写回到实例的 JSON 对象中。
下面示例显示了 JsonExtensionDataAttribute 被应用到一个字段,在反序列化过程中,不匹配的 JSON 属性被添加到字段的集合中。
public class DirectoryAccount
{
// normal deserialization
public string DisplayName { get; set; }
// these properties are set in OnDeserialized
public string UserName { get; set; }
public string Domain { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> _additionalData;
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
// SAMAccountName is not deserialized to any property
// and so it is added to the extension data dictionary
string samAccountName = (string)_additionalData["SAMAccountName"];
Domain = samAccountName.Split('\\')[0];
UserName = samAccountName.Split('\\')[1];
}
public DirectoryAccount()
{
_additionalData = new Dictionary<string, JToken>();
}
}
string json = @"{
'DisplayName': 'John Smith',
'SAMAccountName': 'contoso\\johns'
}";
DirectoryAccount account = JsonConvert.DeserializeObject<DirectoryAccount>(json);
Console.WriteLine(account.DisplayName);
// John Smith
Console.WriteLine(account.Domain);
// contoso
Console.WriteLine(account.UserName);
// johns
2.7、指定构造函数JsonConstructor
JsonConstructorAttribute 可指示 JsonSerializer 在反序列化类时使用特定的构造函数。它可用于使用参数化构造函数而不是默认构造函数创建类,或者在有多个参数化构造函数时选择使用哪个特定的构造函数。
public class User
{
public string UserName { get; private set; }
public bool Enabled { get; private set; }
public User()
{
}
[JsonConstructor]
public User(string userName, bool enabled)
{
UserName = userName;
Enabled = enabled;
}
}
string json = @"{
""UserName"": ""domain\\username"",
""Enabled"": true
}";
User user = JsonConvert.DeserializeObject<User>(json);
Console.WriteLine(user.UserName);
// domain\username
2.8、默认值DefaultValue
public class Invoice
{
public string Company { get; set; }
public decimal Amount { get; set; }
// false is default value of bool
public bool Paid { get; set; }
// null is default value of nullable
public DateTime? PaidDate { get; set; }
// customize default values
[DefaultValue(30)]
public int FollowUpDays { get; set; }
[DefaultValue("")]
public string FollowUpEmailAddress { get; set; }
}
3、回调函数
要告诉序列化器在对象的序列化生命周期中应该调用哪些方法,可以用相应的属性(OnSerializingAttribute、OnSerializedAttribute、OnDeserializingAttribute、OnDeserializedAttribute)来装饰方法。
public class SerializationEventTestObject
{
// 2222
// This member is serialized and deserialized with no change.
public int Member1 { get; set; }
// The value of this field is set and reset during and
// after serialization.
public string Member2 { get; set; }
// This field is not serialized. The OnDeserializedAttribute
// is used to set the member value after serialization.
[JsonIgnore]
public string Member3 { get; set; }
// This field is set to null, but populated after deserialization.
public string Member4 { get; set; }
public SerializationEventTestObject()
{
Member1 = 11;
Member2 = "Hello World!";
Member3 = "This is a nonserialized value";
Member4 = null;
}
[OnSerializing]
internal void OnSerializingMethod(StreamingContext context)
{
Member2 = "This value went into the data file during serialization.";
}
[OnSerialized]
internal void OnSerializedMethod(StreamingContext context)
{
Member2 = "This value was reset after serialization.";
}
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
Member3 = "This value was set during deserialization";
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
Member4 = "This value was set after deserialization.";
}
}
SerializationEventTestObject obj = new SerializationEventTestObject();
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// Hello World!
Console.WriteLine(obj.Member3);
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
// {
// "Member1": 11,
// "Member2": "This value went into the data file during serialization.",
// "Member4": null
// }
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// This value was reset after serialization.
Console.WriteLine(obj.Member3);
// This is a nonserialized value
Console.WriteLine(obj.Member4);
// null
obj = JsonConvert.DeserializeObject<SerializationEventTestObject>(json);
Console.WriteLine(obj.Member1);
// 11
Console.WriteLine(obj.Member2);
// This value went into the data file during serialization.
Console.WriteLine(obj.Member3);
// This value was set during deserialization
Console.WriteLine(obj.Member4);
// This value was set after deserialization.
4、错误处理
错误事件是 JsonSerializer 中的一个事件处理程序。只要在序列化或反序列化 JSON 时出现异常,就会引发错误事件。与 JsonSerializer 上的所有设置一样,它也可以在 JsonSerializerSettings 上设置,并传递给 JsonConvert 上的序列化方法。
List<string> errors = new List<string>();
List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(@"[
'2009-09-09T00:00:00Z',
'I am not a date and will error!',
[
1
],
'1977-02-20T00:00:00Z',
null,
'2000-12-01T00:00:00Z'
]",
new JsonSerializerSettings
{
Error = delegate(object sender, ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
},
Converters = { new IsoDateTimeConverter() }
});
// 2009-09-09T00:00:00Z
// 1977-02-20T00:00:00Z
// 2000-12-01T00:00:00Z
// The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.
// Unexpected token parsing date. Expected String, got StartArray.
// Cannot convert null value to System.DateTime.
4.1、OnErrorAttribute
public class PersonError
{
private List<string> _roles;
public string Name { get; set; }
public int Age { get; set; }
public List<string> Roles
{
get
{
if (_roles == null)
{
throw new Exception("Roles not loaded!");
}
return _roles;
}
set { _roles = value; }
}
public string Title { get; set; }
[OnError]
internal void OnError(StreamingContext context, ErrorContext errorContext)
{
errorContext.Handled = true;
}
}
在本例中,如果没有设置角色,访问 Roles 属性时就会出现异常。HandleError 方法会在序列化 Roles 时将错误设置为已处理,并允许 Json.NET 继续序列化该类。
PersonError person = new PersonError
{
Name = "George Michael Bluth",
Age = 16,
Roles = null,
Title = "Mister Manager"
};
string json = JsonConvert.SerializeObject(person, Formatting.Indented);
Console.WriteLine(json);
//{
// "Name": "George Michael Bluth",
// "Age": 16,
// "Title": "Mister Manager"
//}