小心DataContractJsonSerializer和JavaScriptSerializer的內部實現差異


問題的引子

先來看問題的引子。

定義一個下面這樣的類,此類有Serializable屬性,並且有一個屬性的定義沒有使用自動屬性來實現。

 1 [Serializable]
 2 public class Users
 3 {
 4     public int UserID { get; set; }
 5 
 6     public string UserName { get; set; }
 7 
 8     public string UserEmail { get; set; }
 9 
10     private string _testProperty;
11     public string TestProperty
12     {
13         get { return _testProperty; }
14         set { _testProperty = value; }
15     }
16 }

然后分別使用DataContractJsonSerializer和JavaScriptSerializer對此對象的示例進行序列化。

使用DataContractJsonSerializer序列化后的結果。

{"_testProperty":"TestPropertyValue","<UserEmail>k__BackingField":"parry@cnblogs.com",
"<UserID>k__BackingField":1,"<UserName>k__BackingField":"Parry"}

使用JavaScriptSerializer序列化后的結果。

{"UserID":1,"UserName":"Parry","UserEmail":"parry@cnblogs.com","TestProperty":"TestPropertyValue"}

DataContractJsonSerializer和JavaScriptSerializer的實現差異

DataContractJsonSerializer在.NET Framework 3.5中引入,主要因為WCF的引入而添加了這個對象序列化的基本方法,並且微軟同時將JavaScriptSerializer打上了過時(obsolete)的標簽,編譯時就會有警告出現。

而在.NET Framework 3.5 SP1中,微軟又將JavaScriptSerializer的“過時”標簽給去掉了。

使用Reflector去比較這兩個類的內部實現發現,DataContractJsonSerializer在對象序列化時進行了更為嚴格的檢查,感興趣的可以去System.Runtime.Serialization.Json下面的核心方法InternalWriteObjectContent去看其實現。

而在.NET Framework 3.5引入的自動屬性,實際上就是個語法糖,編譯器還是會生成一個int類型的<Name>k_BackingField的私有字段作為這個屬性的后端字段,內部還是和以前的get/set方法一樣。

所以直接使用DataContractJsonSerializer進行序列化時,又將編譯器生成的k_BackingField帶了出來。

而JavaScriptSerializer的實現則非常簡單,將屬性名和屬性值分別存儲在Dictionary里,然后進行字符串拼接返回而已,所以對類定義幾乎沒有檢查並且對復雜類的支持不太好。

下面是JavaScriptSerializer里面的核心方法SerializeValue的實現。

 1 private void SerializeValue(object o, StringBuilder sb, int depth, Hashtable objectsInUse,
 2 SerializationFormat serializationFormat, MemberInfo currentMember = null) {
 3     if (++depth > _recursionLimit) { 
 4         throw new ArgumentException(AtlasWeb.JSON_DepthLimitExceeded); 
 5     }
 6 
 7     // Check whether a custom converter is available for this type.
 8     JavaScriptConverter converter = null;
 9     if (o != null && ConverterExistsForType(o.GetType(), out converter)) {
10         IDictionary<string, object> dict = converter.Serialize(o, this); 
11 
12         if (TypeResolver != null) { 
13             string typeString = TypeResolver.ResolveTypeId(o.GetType()); 
14             if (typeString != null) {
15                 dict[ServerTypeFieldName] = typeString; 
16             }
17         }
18 
19         sb.Append(Serialize(dict, serializationFormat)); 
20         return;
21     } 
22 
23     SerializeValueInternal(o, sb, depth, objectsInUse, serializationFormat, currentMember);
24 } 

解決方法

如果一定要使用DataContractJsonSerializer,只有當為類加上[DataContract]屬性,並且為需要序列化的屬性加上[DataMember]后,使用DataContractJsonSerializer才可以生成干凈、整潔的JSON數據。

而當我們使用一些不能修改的類定義,如上面的Users類定義,我們沒有權限去修改其定義,那么就可以使用JavaScriptSerializer去進行JSON序列化。

當然第三方的Json.NET(Newtonsoft.Json)也是可以實現的,並且在支持的功能和效率方面往往是一個更好的選擇,在這里看它和DataContractJsonSerializer以及JavaScriptSerializer的使用對比。

所以在使用時需要稍微注意下這三個JSON序列化方法的差異,根據自己的需求靈活選擇合適的組件。


免責聲明!

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



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