上篇文章"理解C# 4 dynamic(2) – ExpandoObject的使用" 了解了ExpandoObject的基本使用。
但ExpandoObject的問題就是它是一個萬金油,什么都可以做,但是又都不專注。
使用DynamicObject正好可以解決這個問題。這篇文章介紹DynamicJson是如何繼承DynamicObject,包裝一個用來處理Json的動態類型。
閱讀目錄:
一、JS可以靈活處理Json字符串
二、DynamicObject分析
三、DynamicJson代碼
四、總結
一,JS可以靈活處理Json字符串
看下面的代碼,
var jsonString='{"foo":"json", "bar":100, "nest":{ "foobar":true }}'; var jsonObj = JSON.parse(jsonString); //接着就能方便的使用 jsonObj.foo jsonObj.nest.foobar
代碼中的jsonObj是動態類型,在.net中,我們也可以反序列化Json,但都需要指定反序列化后的對象類型。
比如使用Json.Net
Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(employee))
有沒有辦法和js一樣,反序列化一個dynamic類型來方便的訪問Json數據?
下面先來看看DynamicObject如何使用,然后使用DynamicObject來實現我們的想法。
二,DynamicObject分析
DynamicObject有個構造函數,但是protected, 也就是我們沒有辦法直接實例化來使用它。只能是通過繼承來構造DynamicObject的對象。
同時DynamicObject中很很多標記為Virtual的方法,比如:
public virtual bool TryGetMember(GetMemberBinder binder, out object result); public virtual bool TrySetMember(SetMemberBinder binder, object value);
當我們寫個類繼承DynamicObject, 這個動態類型類的對象,所具有的特性,就是通過重寫這些virtual方法體現出來的。
假設SampleObject 是繼承DynamicObject的類,那么
如果我們重寫了TryGetMember, 在調用 int number = sampleObject.Number.時,就會調用TryGetMemeber方法來得到返回值。
如果我們重寫了TrySetMember,在調用sampleObject.Number = number 時使用,就會調用TrySetMember方法。
了解了DynamicObject, 我們的路線就更加清晰了:
我們要寫一個類DynamicJson,繼承自DynamicObject
DynamicJson有靜態Parse方法,接受一個Json的字符串,返回DynamicJson的對象。
DynamicJson重寫TryGetMember方法,這樣當訪問屬性的時候,我們處理,返回正確的值。
三,DynamicJson代碼
DynamicJson正是這個思路實現的,下面來分析一下DynamicJson中一些關鍵代碼
Parse靜態方法
這段代碼非常容易理解,這里將json以xml方式處理,屬性變成了xml中的element處理
public static dynamic Parse(string json) { using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.Unicode.GetBytes(json), XmlDictionaryReaderQuotas.Max)) { return ToValue(XElement.Load(reader)); } }
ToValue方法
To value方法根據json反序列化后的xml信息,獲取element的type屬性,然后根據屬性分別處理。
如果是非數組和object類型,就直接返回。
如果是,就返回DynamicJson對象,這樣當我們使用對象的屬性,就會調用TryGetMember方法
private static dynamic ToValue(XElement element) { var type = (JsonType)Enum.Parse(typeof(JsonType), element.Attribute("type").Value); switch (type) { case JsonType.boolean: return (bool)element; case JsonType.number: return (double)element; case JsonType.@string: return (string)element; case JsonType.@object: case JsonType.array: return new DynamicJson(element, type); case JsonType.@null: default: return null; }
}
TryGetMember方法
下面是重寫的TryGetMember方法
public override bool TryGetMember(GetMemberBinder binder, out object result) { //根據訪問的屬性,在序列化的xml結構中尋找子element. var element = xml.Element(binder.Name); if (element == null) { result = null; return false; } result = ToValue(element);//如果存在該element, 就繼續調用ToValue, 如果是普通類型,就能夠返回具體的內容,如果是數組或object,就在返回一個DynamicJson對象。 return true; }
四,總結
DynamicJson的代碼實現的功能很多,詳細的DynamicJson的代碼,可以通過Nuget獲取。
通過繼承DynamicObject類,實現了非常多的功能類,
有針對Json的DynamicJson,還有針對xml的DynamicXml
使用它們,減少了不必要的類型定義,增加了程序代碼的靈活性。