DataContractJsonSerializer和JavaScriptSerializer內部實現差異

weixin_34391854發表於2015-06-16

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

[Serializable]
 public class Users
 {
     public int UserID { get; set; }
     public string UserName { get; set; }
     public string UserEmail { get; set; }
     private string _testProperty;
     public string TestProperty
     {
         get { return _testProperty; }

         set { _testProperty = value; }
     }
 }


然後分別使用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的實現。

private void SerializeValue(object o, StringBuilder sb, int depth, Hashtable objectsInUse,
 SerializationFormat serializationFormat, MemberInfo currentMember = null) {
     if (++depth > _recursionLimit) {
         throw new ArgumentException(AtlasWeb.JSON_DepthLimitExceeded);
     }
     // Check whether a custom converter is available for this type.
     JavaScriptConverter converter = null;
     if (o != null && ConverterExistsForType(o.GetType(), out converter)) {
         IDictionary<string, object> dict = converter.Serialize(o, this);
         if (TypeResolver != null) {
             string typeString = TypeResolver.ResolveTypeId(o.GetType());
             if (typeString != null) {
                 dict[ServerTypeFieldName] = typeString;
             }
         }
         sb.Append(Serialize(dict, serializationFormat));
         return;
     }
     SerializeValueInternal(o, sb, depth, objectsInUse, serializationFormat, currentMember);
 }


解決方法:

如果一定要使用DataContractJsonSerializer,只有當為類加上[DataContract]屬性,並且為需要序列化的屬性加上[DataMember]後,使用DataContractJsonSerializer才可以生成乾淨、整潔的JSON資料。
而當我們使用一些不能修改的類定義,如上面的Users類定義,我們沒有許可權去修改其定義,那麼就可以使用JavaScriptSerializer去進行JSON序列化。
當然第三方的Json.NET(Newtonsoft.Json)也是可以實現了,並且在支援的功能和效率方面往往是一個更好的選擇,在這裡看它和DataContractJsonSerializer以及JavaScriptSerializer的對比。
所以在使用時需要稍微注意下這三個JSON序列化方法的差異,根據自己的需求靈活選擇合適的元件。

相關文章