導航目錄:
一:Newtonsoft.Json 支持序列化與反序列化的.net 對象類型;
二:C#對象、集合、DataTable與Json內容互轉示例;
前面兩篇分別介紹了C#轉換JSON時一些常規的用法,以前我也是,只用到了前面這些比較常用的方法,沒想到在轉換時還有那么多特殊的設置,
今天這篇內容就來講一下一些特殊的設置,比如,轉換時過濾掉個別屬性、重命名字段名稱、枚舉字段的處理、私有變量的轉換等;
好了,開始今天的正題:
序列化時忽略特定的屬性字段
需求分析:有時候在前后台或者APP直接進行數據交互的時候,不需要全部的屬性內容,舉個栗子,比如,只想知道用戶的名字叫啥,如果把用戶的年齡、
性別,愛好都返回,中間的傳輸過程就會占用寬帶,而且,其它的字段也不需要,也浪費了轉換的性能。SO,還是前面文章中的對象類,咱們改進下,比
如,現在我們只想要這個用戶的名字叫啥,代碼怎么改呢?
有兩種方式可以實現,方式1:比如你去飯店,告訴老板我要這個菜,這個菜,還有那個菜。
[JsonObject(MemberSerialization.OptIn)] //這個標簽定義了你的選菜方式,只選我要的 public class PeopleInfo { [JsonProperty] //這個標簽標記了這個是你要選擇的菜品 public string Name { get; set; } [JsonProperty] //這個標簽標記了這個是你要選擇的菜品 public int Age { get; set; } public DateTime Birthday { get; set; } public EnumGender Gender { get; set; } public List<string> Hobby { get; set; } }
【OptIn情況下,默認是將所有的屬性都定義成了不要,如果這個屬性需要轉換成Json,需要標記JsonProperty】
轉換后的結果:
方式2:就是你去飯店,告訴老板我不要這個菜,不要這個菜。
[JsonObject(MemberSerialization.OptOut)] //這個標簽定義了你的選菜方式,排除我不要的 public class PeopleInfo { public string Name { get; set; } [JsonIgnore] //這個標簽標記了這個不是要想要的菜品 public int Age { get; set; } [JsonIgnore] //這個標簽標記了這個不是要想要的菜品 public DateTime Birthday { get; set; } public EnumGender Gender { get; set; } public List<string> Hobby { get; set; } }
【OptOut情況下,默認是將所有的屬性都定義成了要轉換Json,如果這個屬性不需要轉換成Json,需要標記JsonIgnore】
序列化時更改(重命名)屬性名稱;
需求分析:有時候實體類中定義的屬性名稱可能不是想要的名稱,但是又不能更改實體類中屬性的名稱,這個時候就可以自定義序列化字段名稱。
這就好比,飯店里面的一道菜菜單叫螞蟻上樹,實際上就是一道粉絲炒肉末,螞蟻上樹就是重命名的屬性名稱,粉絲炒肉末才是它的實體類名稱;
還是復用前面的代碼,稍微修改下:
public class PeopleInfo { [JsonProperty(PropertyName = "名稱")] //寫法1 public string Name { get; set; } [JsonProperty("年齡")] //寫法2 public int Age { get; set; } public DateTime Birthday { get; set; } public EnumGender Gender { get; set; } public List<string> Hobby { get; set; } }
轉換后的結果:
序列化時將非公共變量(private)轉換為Json;
分析:一般情況下,在進行Json轉換的時候,只會對public 成員進行Json轉換,默認情況下,私有成員是不轉換的。
只需要在屬性上標記[JsonProperty]就可以了。如下圖:
序列化時忽略空值的屬性字段;
分析:上上面的例子中,Name字段為Null值,假如實際前后端數據交互中,Null值的數據返回豈不是很沒有意義?為此,我們
可以設置下,如果值為Null值時,就不進行序列化轉換。
方式1:在屬性成員中指定NullValueHandling方式。
【NullValueHandling:這是每個枚舉值,Ignore忽略空值,Include包含空值】
方式2:通過上面的示例,我們可以發現,可以對單個屬性進行設置,如果一個實體類有20個屬性成員,30個屬性成員,然后,
一個一個去設置豈不是很二,有沒有更高效的方式呢?答案是當然有的啦,看下面,這個方式就不需要在單獨對每一個屬性進行設置了。
代碼:
private void btnJsonDemo_Click(object sender, EventArgs e) { PeopleInfo p = new PeopleInfo(); //p.Name = "李家村的二狗子"; //沒有對Name屬性賦值,Name值為Null值 p.Age = 30; p.Birthday = DateTime.Now; p.Gender = EnumGender.male; p.Hobby = new List<string> { "寫Bug", "釣魚", "看新聞聯播" }; JsonSerializerSettings setting = new JsonSerializerSettings(); setting.NullValueHandling = NullValueHandling.Ignore; //設置全局的Null值處理,JsonSerializerSettings竟然沒有構造函數,一點都不OOP string json = JsonConvert.SerializeObject(p, setting); this.txtResult.Text = json; }
轉換結果如下圖:
序列化時枚舉值的處理;
分析:在上面的例子中,所轉換的Gender都是int類型的,假如,我們在轉換Json時需要轉換成對應的字符怎么操作呢?
代碼:[JsonConverter(typeof(StringEnumConverter))]
根據條件來設置屬性是否序列化;
Json.NET能夠通過在類上放置ShouldSerialize方法來有條件地序列化屬性,要有條件地序列化屬性,需要在對象類中增加一個
與該屬性同名的布爾值的方法,然后使用ShouldSerialize作為方法名稱的前綴,比如你要設置屬性字段Name根據條件來動態決
定是否序列化,則方法名一定要寫成ShouldSerializeName()。方法的返回值必須是bool類型,如果返回true,表示這個屬性可以
序列化,返回false表示不被序列化。
還用以前的PeopleInfo 類,稍微改進下:
public class PeopleInfo { public string Name { get; set; } public int Age { get; set; } public DateTime Birthday { get; set; } public EnumGender Gender { get; set; } public List<string> Hobby { get; set; } //注意方法名稱以及方法類型 public bool ShouldSerializeName() { if (this.Name == "李四") //如果名稱是李四,則Name屬性不序列化 return false; return true; } }
調用方法:
List<PeopleInfo> list = new List<PeopleInfo>(); PeopleInfo p = new PeopleInfo(); p.Name = "李二狗"; p.Age = 30; p.Birthday = DateTime.Now; p.Gender = EnumGender.male; p.Hobby = new List<string> { "寫Bug", "釣魚", "看新聞聯播" }; list.Add(p); PeopleInfo p1 = new PeopleInfo(); p1.Name = "李四"; p1.Age = 30; p1.Birthday = DateTime.Now; p1.Gender = EnumGender.male; p1.Hobby = new List<string> { "工作" }; list.Add(p1); string json = JsonConvert.SerializeObject(list); this.txtResult.Text = json;
轉換結果如下圖:
問題升級:如果需要兩個或者多個屬性都可以根據條件來序列化?難道要寫很多個方法?
根據條件來設置多個屬性是否序列化;
針對上面的問題,如果有多個屬性需要根據條件來序列化怎么辦?我們可以新增一個方法,如下:
public class LimitPropsContractResolver : DefaultContractResolver { string[] Propertys = null; bool IsSerialize; public LimitPropsContractResolver(string[] props, bool retain = true) { this.Propertys = props; this.IsSerialize = retain; } protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { IList<JsonProperty> list = base.CreateProperties(type, memberSerialization); return list.Where(p => { if (IsSerialize) { return Propertys.Contains(p.PropertyName); } else { return !Propertys.Contains(p.PropertyName); } }).ToList(); } }
調用的時候,只需要把字段名稱傳入string數組中就可以,bool值表示是否需要轉換此字段;調用方法如下:
JsonSerializerSettings settings = new JsonSerializerSettings(); settings.ContractResolver = new LimitPropsContractResolver(new string[] { "Gender", "Hobby" }, false); string json = JsonConvert.SerializeObject(list, settings);
參考:
官方:https://github.com/JamesNK/Newtonsoft.Json
官方文檔:https://www.newtonsoft.com/json/help/html/Introduction.htm
https://www.cnblogs.com/leonsky/p/3300511.html
http://www.cnblogs.com/yanweidie/p/4605212.html#_label2
感謝官方以及部分原文作者。