1. 程式人生 > >Newtonsoft—Json.NET常用方法簡述

Newtonsoft—Json.NET常用方法簡述


 

Json.NET常用方法彙總(可解決日常百分之90的需求)

0.Json.NET基礎用法

  首先去官網下載最新的Newtonsoft.Json.dll(也可以使用VS自帶的NuGet搜尋Json.NET下載(下載下圖第二個))並引用至專案。

  

  • (1)序列化實體類(將實體類物件序列化為Json字串)
using System;
using Newtonsoft.Json;

namespace Json_NET_Test
{
    /// <summary>
    /// 定義一個實體類
    /// </summary>
    public class Student
    {
        public string Name;
        public int Age;
        public string Class;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //建立實體類物件           
            Student stu = new Student
            {
                Name = "老王",
                Age = 99,
                Class = "三班"
            };
            //開始序列化
            string jsonStr = JsonConvert.SerializeObject(stu, Formatting.Indented);
            Console.WriteLine(jsonStr);
        }
    }
}

  結果:

  

  • (2)反序列化(將Json字串反序列化為實體類物件)
using System;
using Newtonsoft.Json;

namespace Json_NET_Test
{
    /// <summary>
    /// 定義一個實體類
    /// </summary>
    public class Student
    {
        public string Name;
        public int Age;
        public string Class;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Json字串
            string jsonStr = "{\"Name\": \"老王\",\"Age\": 99,\"Class\": \"三班\"}";
            //開始反序列化
            Student stu = JsonConvert.DeserializeObject<Student>(jsonStr);
        }
    }
}

1.序列化與反序列化時忽略某些屬性

  • (1)忽略類內所有屬性

  [JsonObject(MemberSerialization.OptIn)]用於在序列化與反序列化時忽略一個類裡所有的屬性,只有當在類內屬性上打特性標籤[JsonProperty]時才支援序列化與反序列化。所以[JsonObject(MemberSerialization.OptIn)]常用於與[JsonProperty]配合使用。

  例:

[JsonObject(MemberSerialization.OptIn)]
public class Person
{
    public int Age { get; set; }

    [JsonProperty]
    public string Name { get; set; }

    public string Sex { get; set; }

    public bool IsMarry { get; set; }

    public DateTime Birthday { get; set; }
}
  • (2)序列化所有屬性(預設)

  預設實體類上預設打著[JsonObject(MemberSerialization.OptOut)]特性標籤(可以省略不寫),如果要忽略某些屬性,要在屬性上打[JsonIgnore]。

  例:

[JsonObject(MemberSerialization.OptOut)]
public class Person
{
    public int Age { get; set; }

    public string Name { get; set; }

    public string Sex { get; set; }

    [JsonIgnore]
    public bool IsMarry { get; set; }

    public DateTime Birthday { get; set; }
}
  • (3)動態控制實體類屬性的是否忽略序列化(預設)

  當某些條件下需要序列化A屬性和B屬性,某些情況下需要忽略A屬性與B屬性,我們該怎麼做?
  答:使用JsonSerializerSettings設定某實體類物件要忽略序列化的屬性(配合if與else控制屬性的動態忽略)。

  例:以下方式忽略p物件的Age屬性與IsMarry屬性:

JsonSerializerSettings jsetting=new JsonSerializerSettings();
jsetting.ContractResolver = new LimitPropsContractResolver(new string[] { "Age", "IsMarry" });
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

 


 

2.預設值處理

  • (1)設定屬性預設值

  在屬性上打 [DefaultValue("xxx")]

 


 

3.空值處理

  • (1)不序列化為null的屬性(使用JsonSerializerSettings方式)
    Person p = new Person 
    { 
         room = null,
         Age = 10, 
         Name = "張三丰", 
         Sex = "男", 
         IsMarry = false, 
         Birthday = new DateTime(1991, 1, 2) 
    };
    JsonSerializerSettings jsetting=new JsonSerializerSettings();
    jsetting.NullValueHandling = NullValueHandling.Ignore;
    Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

  ps:使用這種方式可能bool為false的也無法序列,最後的結果只包含Birthday、Sex、Name、Age。

  • (2)不序列化為null的屬性(使用特性標籤方式)
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public Room room { get; set; }

 

 


 

4.序列化私有成員

  因為預設只序列化public的成員,所以如果想序列化private成員,要在實體類的屬性上打[JsonProperty]標籤。

[JsonProperty]
private int Height { get; set; }

 


 

5.自定義序列化名稱

  在序列化與反序列化時可以自定義序列化出字串的屬性名稱,如下程式碼可以將實體類的Name屬性序列化為CName屬性,並且可以將Json中的CName反序列化為當前實體類的Name屬性。(雙向)

[JsonProperty(PropertyName = "CName")]
public string Name { get; set; }

 


 

6.日期處理

  • (1)解決方案1:在可以動Model程式碼的情況下

  系統自帶的DateTime會格式化成iso日期標準,但是實際使用過程中大多數使用的可能是yyyy-MM-dd 或者yyyy-MM-dd HH:mm:ss兩種格式的日期,解決辦法是可以將DateTime型別改成string型別自己格式化好,然後在序列化。
  例:

    [JsonProperty(PropertyName = "startTime")]//因為預設只序列化public屬性,所以要打上JsonProperty標籤並且宣告名稱
    private string m_StartTime{get;set;}

    [JsonIgnore]//這個標籤用於在序列化與反序列化時忽略StartTime屬性
    public DateTime StartTime
    {
        get{ return Convert.ToDateTime(m_StartTime); }
        set
        {
            DateTime time = value;
            m_StartTime = time.ToString("yyyy-MM-dd");//這裡寫自己想要的格式
        }
    }

  ps:程式碼思路是不去序列化StartTime屬性,而去序列化string型別的m_StartTime屬性(m_StartTime相當於StartTime屬性的私有欄位)。

  • (2)解決方案2:使用DateTimeConverterBase

  Json.Net提供了IsoDateTimeConverter日期轉換這個類,可以通過JsnConverter實現相應的日期轉換

[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime Birthday { get; set; }

   但是IsoDateTimeConverter日期格式(yyyy-MM-ddTHH:mm:ss)不是我們想要的,我們可以繼承該類實現自己的日期
  例:

    public class ChinaDateTimeConverter : DateTimeConverterBase
    {
        private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" };

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            dtConverter.WriteJson(writer, value, serializer);
        }
    }

  使用方式:

[JsonConverter(typeof(ChinaDateTimeConverter))]
public DateTime Birthday { get; set; }

 


 

7.以駝峰命名法序列化

  有時我們會碰到這種需求,比如我們程式碼裡實體型別的屬性名稱均是以大寫字母開頭,如Name、StartTime等,但是要求我們序列出的Json字串的屬性名稱要以小寫字母開頭,如name、startTime、endTime等。我們可以使用如下程式碼解決

JsonSerializerSettings setting = new JsonSerializerSettings();
setting.ContracResolver = new CamelCasePropertyNamesContractResolver();
string jsonStr = JsonConvert.Serializeobject(p, Newtonsoft.json.Formatting.Indented, setting);

  這樣子的話,在序列實體類物件p的屬性時,屬性名稱將由PersonName轉換為personName。

 


 

8.列舉的序列化
  列舉預設序列化為列舉的Int值,如果想要序列化為列舉string值,使用如下方式

   [JsonConverter(typeofpublic NotifyTypeEnum Type { get; set; }  

 


 

9.使用JsonConverter自定義屬性序列化規則(json格式轉換器)

  • (1)將屬性值由double型別序列化時轉為字串型別
  public class DoubleToStringConverter : JsonConverter
    {
        //表示反序列化時不執行該轉換器
        public override bool CanRead => false;
        //表示序列化時執行該轉換器
        public override bool CanWrite => true;

        //判斷執行條件(當屬性的值為double型別時才使用轉換器)
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(double);
        }

        //因為public override bool CanRead => false;,所以不用實現反序列化時的轉換方法
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 序列化時執行的轉換
        /// </summary>
        /// <param name="writer">可以用來重寫值</param>
        /// <param name="value">屬性的原值</param>
        /// <param name="serializer">就是那個serializer物件</param>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            double v = (double)value;
            writer.WriteValue(v.ToString());
        }
    }

  使用方式:

[JsonConverter(typeof(DoubleToStringConverter))]
public double Count{get;set;}

  ps:這樣子,就可以把原本序列化出的Json字串   Count : 12.3   轉化為   Count : "12.3"
  ps:[JsonConverter(typeof(DoubleToStringConverter))]也可以打在類上,表示全域性設定

  • (2)列舉轉換為int字串

 

  為什麼要進行這樣的轉換呢?

  因為列舉型別在序列化時預設序列化為列舉的int型別,即如下程式碼:

   /// <summary>
    /// 自定義一個列舉型別
    /// </summary>
    public enum MyEnum
    {
        aaa = 1,
        bbb = 2,
        ccc = 3
    }
    /// <summary>
    /// 實體類(類內有一個列舉型別的屬性MyEnumProp)
    /// </summary>
    public class Person
    {
        public MyEnum MyEnumProp { get; set; }
    }
    class Program
    {

        static void Main(string[] args)
        {
            Person p = new Person() { MyEnumProp = MyEnum.ccc };
            //Json字串
            string jsonStr = JsonConvert.SerializeObject(p);
            //開始反序列化
            Console.WriteLine(jsonStr);
            Console.ReadLine();
        }
    }

  結果為:

  

 

   有時候會有這樣的需求,序列化出的屬性值均要為字串格式,即要將上圖結果的3改為"3"。這時候就需要自定義轉換了!

  程式碼如下:

    public class EnumToIntStringConverter : JsonConverter
    {
        //反序列化時不執行
        public override bool CanRead => false;
        //序列化時執行
        public override bool CanWrite => true;

        //控制執行條件(當屬性的值為double型別時才使用轉換器)
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Enum);
        }

        //因為public override bool CanRead => false;,所以不用實現反序列化時的轉換方法
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 序列化時執行的轉換
        /// </summary>
        /// <param name="writer">可以用來重寫值</param>
        /// <param name="value">屬性的原值</param>
        /// <param name="serializer">就是那個serializer物件</param>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Enum e = (Enum)value;
            int v = Convert.ToInt32(e);
            writer.WriteValue(v.ToString());
        }
    }  

  使用方法同上例。

&n