Newtonsoft.Json使用


序列化與反序列化

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));

參考:

C# JArray與JObject 的使用

C# 關於JArray和JObject封裝JSON對象

問題

1、平方² 保存到文件變成了2

鍵盤輸入平方(m²)或立方(m³)等特殊字符

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`字段,並在其中引發異常,如果檢查失敗。

 參考:https://learn.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json/handle-overflow?pivots=dotnet-6-0

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類的屬性上分別使用了JsonPropertyRequired屬性。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)]`特性,確保在反序列化時字段一一匹配,缺失的部分會報錯。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM