JSON的序列化和反序列化已經成為Web開發必不可少的知識。現在常用的有System.Web.Script.Serialization下的JavaScriptSerializer來進行處理;另外一個比較常用且高效的類庫是JSON.NET。
在開發一些小的應用時,由於想盡量較少項目的依賴,所以不太願意使用JSON.NET。JavaScriptSerializer基本上能滿足簡單的需求,但當一個屬性要序列化成別的名字時,就顯得力不從心了。還有就是可能業務需要,某些屬性不希望在某一個條件下進行序列化。鑒於上面的業務需要,我們就需要自定義一個JavaScriptConverter。
自定義JavaScriptConverter的使用流程:
- 定義一個JavaScriptConverter,指明期支持的類型。
- 在序列化方法調用前注冊該轉換器。
顯然,這兩個步驟都不是很麻煩。我們舉一個具體的業務環境來說明:在ExtJS的TreePanel控件中,TreeNode的屬性有id、text等,其中如果checked屬性存在,則屬性結果顯示節點選擇框。在C#中,checked是關鍵字,所以不能定義為屬性,TreeNode的C#代碼如下:
public class TreeNode { public string id { get; set; } public string text { get; set; } public bool? isChecked { get; set; } public List<TreeNode> children { get; set; } }
我將checked屬性映射到類中的isChecked字段,該字段可以有三個狀態:null、true和false,當為null的時候,將不會序列化該字段,前台也不會顯示節點選擇框。
現在要實現一個TreeNodeJSConverter,代碼如下:
public class TreeNodeJSConverter : JavaScriptConverter { public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { TreeNode node = new TreeNode(); object value = null; if (dictionary.TryGetValue("id", out value)) node.id = (string)value; if (dictionary.TryGetValue("text", out value)) node.text = (string)value; if (dictionary.TryGetValue("children", out value)) { if (value != null && value.GetType() == typeof(ArrayList)) { var list = (ArrayList)value; node.children = new List<TreeNode>(); foreach (Dictionary<string, object> item in list) { node.children.Add((TreeNode)this.Deserialize(item, type, serializer)); } } else { node.children = null; } } return node; } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { Dictionary<string, object> dic = new Dictionary<string, object>(); var node = obj as TreeNode; if (node == null) return null; if(!string.IsNullOrEmpty(node.id)) dic.Add("id", node.id); if (!string.IsNullOrEmpty(node.text)) dic.Add("text", node.text); if (node.isChecked.HasValue) dic.Add("checked", node.isChecked.Value); if (node.children != null) dic.Add("children", node.children); return dic; } public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(TreeNode) }; } } }
代碼討論:TreeNodeJSConverter類首先需要繼承JavaScriptConverter,然后實現它的相關方法:Deserialize、Serialize和SupportedTypes,分別是反序列化、序列化和支持的類型。
在序列化方法Serialize中,我們需要將屬性添加到一個字典結構中,就可以完成序列化的工作了。具體要序列化那些字段還是要判斷一下相應的值是否存在。
在反序列化方法Deserialize中,字典結構存放着相應的值,當值存在的時候就可以為TreeNode相應的字段賦值。比較麻煩的事children屬性,因為其為嵌套的List類型,而JSON中的數組結構會被轉化成ArrayList結構,所以我們只需要遞歸的循環ArrayList中的每一個項,將其轉換為TreeNode就可以了。
最后是SupportedTypes字段,返回支持的類型,我們這里顯示的返回TreeNode的類型。
定義好了轉換器之后,我們需要為在序列化的時候注冊該轉換器即可:
public static string SerializeToJson(object obj) { JavaScriptSerializer serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new JavaScriptConverter[] { new TreeNodeJSConverter() }); return serializer.Serialize(obj); } public static T DeserializeJson<T>(string jsonString) { JavaScriptSerializer serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new JavaScriptConverter[] { new TreeNodeJSConverter() }); return serializer.Deserialize<T>(jsonString); }
代碼中標紅的部分就是注冊轉化器的地方,用起來很方便,代碼都貼出來了,不再提供源碼下載了。。親,早點睡吧!