序列化與反序列化
1、反序列化是不區分大小寫的
以下代碼可以正常運行
public static void Test() { //反序列化時 不區分大小寫的 string jsonString = "{\"name\":\"張三\",\"age\":18,\"sex\":\"男\"}"; var model = JsonConvert.DeserializeObject<PersonJson>(jsonString); if (model != null) { Console.WriteLine(model.Name); } } public class PersonJson { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } }
2、序列化
若想不區分大小寫,參考:使用Newtonsoft.Json進行Json序列化忽略首字母大小寫,Json字符串反序列化到子集對象(C#)
JObject 用法 、JProperty 用法、JArray 用法
使用LINQ to JSON前,需要引用Newtonsoft.Json的dll和using Newtonsoft.Json.Linq的命名空間。
LINQ to JSON主要使用到JObject, JArray, JProperty和JValue這四個對象,
- JObject用來生成一個JSON對象,簡單來說就是生成”{}”,
- JArray用來生成一個JSON數組,也就是”[]”,
- JProperty用來生成一個JSON數據,格式為key/value的值,
- 而JValue則直接生成一個JSON值
簡單示例:
JArray jo1 = (JArray)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(list)); JObject a1 = (JObject)resultJson["group"][times]; a1.Add(new JProperty("list", jo1));
參考:
問題
1、平方² 保存到文件變成了2
var test =new {name ="速度(m/²)"};
注意: File.WriteAllText()是,編碼要設置為Encoding.UTF8,而不能是Default。
2、json字符串和 對象(復雜對象) 相互解析時,字段一一匹配的問題
2.1 MissingMemberHandling可以解決 對象中缺少 Json字符串中定義的字段
並通過使用`JsonExtensionData`特性和`Dictionary<string, JToken>`類來捕獲未解析的JSON屬性
JsonSerializerSettings jss = new JsonSerializerSettings(); jss. MissingMemberHandling = MissingMemberHandling.Error; string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj, Formatting.Indented, jss);
使用`Newtonsoft.Json`將字符串轉換為對象時,確保對象中的所有字段在字符串中都能找到的寫法是在`DeserializeObject`方法的第二個參數中添加一個`JsonSerializerSettings`對象,並將其`MissingMemberHandling`屬性設置為`MissingMemberHandling.Error`。這樣,當字符串中的字段沒有對應到對象的屬性時,將會拋出異常。
以下是示例代碼:
```csharp
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
string json = @"{""Name"":""Tom"",""Age"":30,""Gender"":""male""}"; // 假設字符串中有一個未定義的 Gender 字段
JsonSerializerSettings settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error // 指定 MissingMemberHandling 屬性為 Error
};
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 進行字符串轉換為對象
```
在此示例中,我們定義了一個`Person`類,並初始化了一個包含未定義的`Gender`字段的JSON字符串。在調用`DeserializeObject`方法時,我們將第二個參數`settings`設置為一個包含`MissingMemberHandling`屬性的`JsonSerializerSettings`對象,並將其值設置為`MissingMemberHandling.Error`,這將會在字符串中有未定義字段的情況下引發異常。最后,我們調用`DeserializeObject`方法將JSON字符串轉換為`Person`對象,如果字符串中包含未定義字段,則會引發異常。
可以捕獲哪些沒有 解析的字段:
如果對象中的字段比字符串中的字段多,可以創建`JsonSerializerSettings`對象,並將其`MissingMemberHandling`屬性設置為`MissingMemberHandling.Error`。這將會在反序列化過程中引發異常,以指示缺少的成員或JSON屬性。
另一種方法是使用`JsonExtensionData`特性和`Dictionary<string, JToken>`類來捕獲未解析的JSON屬性。使用`JsonExtensionData`特性和`Dictionary<string, JToken>`類,可以在定義時不需要知道有哪些未解析的JSON屬性(因為它們存儲在字典中)。
【這種方式 只能檢測:字符串比對象多的情況,字符串中多了的會放在 ,字典中】
以下是示例代碼:
```csharp
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> additionalProperties;
public void Validate()
{
if (additionalProperties != null && additionalProperties.Count > 0)
{
throw new JsonSerializationException(string.Format("未解析的 JSON 屬性: {0}", string.Join(",", additionalProperties.Keys)));
}
}
}
string json = @"{""Name"":""Tom"",""Age"":30,""Gender"":""male""}"; // 字段 "Gender" 對象中未定義
JsonSerializerSettings settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error // 設置 MissingMemberHandling 屬性
};
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 進行反序列化
person.Validate(); // 檢查格式是否正確
```
在此示例中,我們定義了一個`Person`類,用於存儲JSON對象的屬性。在這個類中,我們將`additionalProperties`字段使用`JsonExtensionData`特性標記為擴展數據。當使用`DeserializeObject`方法將JSON字符串轉換為`Person`對象時,所有未在類定義中列出的屬性都將存儲在`additionalProperties`字典中。我們定義了一個`Validate`方法來檢查`additionalProperties`字段,並在其中引發異常,如果檢查失敗。
2.2 結合JsonProperty
特性和Required
屬性,解決 Json中缺少 對象中定義的字段
需要結合JsonProperty
特性和Required
屬性來解決。使用JsonProperty
特性可以映射Json字典中的屬性名,同時,可以使用Required
屬性,它會強制要求在 JSON 字典中具有指定的屬性。只要Required
屬性將其設置為true
,則在反序列化過程中如果缺少其對應的屬性,則會拋出異常。
using Newtonsoft.Json; public class Person { public string Name { get; set; } public int Age { get; set; } [JsonProperty(Required = Required.Always)] public Student Std { get; set; } } public class Student { public int Id { get; set; } [JsonProperty(Required = Required.Always)] public int Parent { get; set; } } string json = @"{""Name"":""Tom"",""Age"":30,""Std"":{""Id"":12}}"; // 缺少 "Parent" 屬性 Person person = JsonConvert.DeserializeObject<Person>(json); // 進行反序列化
在此示例中,我們在Person
類和Student
類的屬性上分別使用了JsonProperty
和Required
屬性。Required
屬性的值設置為Required.Always
,表示在JSON字符串中必須包含此屬性。由於JSON字符串缺少Parent
屬性,當我們使用JsonConvert.DeserializeObject
方法將JSON字符串轉換為Person
對象時,將拋出異常。
總之,使用JsonProperty
特性和Required
屬性可以解決JSON字符串中少字段的問題,確保在反序列化時字段一一匹配,缺失的部分會報錯。
2.3 對所有 屬性打特性
假如一個復雜對象有上百個字段,所有字段都需要注明[JsonProperty(Required = Required.Always)],該如何寫?
如果一個復雜對象有很多字段,每個字段都需要使用`[JsonProperty(Required = Required.Always)]`特性來強制要求在 JSON 字典中有對應的屬性,那么我們可以使用屬性標記器來對所有的屬性進行統一標記。具體步驟如下:
1.定義一個自定義特性,用於在所有屬性上注明`[JsonProperty(Required = Required.Always)]`特性:
```csharp
[AttributeUsage(AttributeTargets.Property)]
public class RequiredJsonPropertyAttribute : Attribute { }
```
2.在所有要求強制要求在 JSON 字典中有對應的屬性的屬性上,標記自定義特性,如下所示:
```csharp
public class Person
{
[RequiredJsonProperty]
public string Name { get; set; }
[RequiredJsonProperty]
public int Age { get; set; }
[RequiredJsonProperty]
public Student Std { get; set; }
// ...
}
```
3.在反序列化對象之前,使用反射來為所有打了標記的屬性添加`[JsonProperty(Required = Required.Always)]`特性,具體實現如下:
```csharp
using Newtonsoft.Json;
using System.Linq;
using System.Reflection;
public class MyJsonConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
RequiredJsonPropertyAttribute attribute = property.GetCustomAttribute<RequiredJsonPropertyAttribute>();
if (attribute != null)
{
JsonPropertyAttribute jsonAttribute = property.GetCustomAttributes(true).OfType<JsonPropertyAttribute>().FirstOrDefault();
if (jsonAttribute == null)
{
jsonAttribute = new JsonPropertyAttribute();
}
jsonAttribute.Required = Required.Always;
property.SetCustomAttribute(jsonAttribute);
}
}
serializer.Populate(reader, instance);
return instance;
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override bool CanWrite
{
get { return false; }
}
}
```
以下是使用示例:
```csharp
string json = @"{""Name"":""Tom"",""Age"":30,""Std"":{""Id"":12}}"; // 缺少 "Parent" 屬性
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new MyJsonConverter());
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 進行反序列化
```
在此示例中,我們首先定義了一個名為`RequiredJsonPropertyAttribute`的自定義特性,並將其用於在所有應強制要求在JSON字典中具有相應屬性的屬性上。然后,我們創建了一個派生自`JsonConverter`的自定義JSON轉換器,名為`MyJsonConverter`。在`ReadJson`方法中,我們通過反射遍歷所有打了特性標記`[RequiredJsonProperty]`的屬性,並添加到`[JsonProperty(Required = Required.Always)]`特性中來強制要求在JSON字典中存在相應的屬性。最后,使用`settings.Converters.Add`方法將`MyJsonConverter`對象添加到`JsonConvert.DeserializeObject`方法的設置參數中。
總之,使用自定義特性與反射技術,可以用這種方式輕松地為所有復雜對象的屬性添加`[JsonProperty(Required = Required.Always)]`特性,確保在反序列化時字段一一匹配,缺失的部分會報錯。