C_Sharp 板


LINE

Serialization 或稱 Persistance 是一種將物件保存的機制,透過這套機制 可以將物件保存在檔案中,再需要時再還原物件的狀態。 .NET有直接支援Serialize,任何class只要標記[Serializable]就具備了 Serialize的能力,所有的Fiels(public, private, protected, static..) 都會在程式呼叫IFormatter.Serialize()的時候被保存下來,在程式呼叫 IFormatter.Deserialize()時從stream中建立class的instance。 關於這些基本的概念MSDN文件上都有相當詳細的說明,這邊就簡單的帶過 [Serializable] SerializableAttribute class的簡寫 [AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited=false)] public sealed class SerializableAttribute : Attribute 由上面的宣告我們可以知道[Serializable]對象為 1.Class 2.Struct 3.Enum 4.Delegate 且沒有繼承的效果(Inherited = false),這點很重要稍後會討論。 一般而言標示了[Serializable]通常不用任何處理就可以完成大部分 Serialize的工作了。 [NonSerialized] NonSerializedAttribute class的簡寫用來指示Field不用 在執行Serialize時存到stream中。 ISerializable 用來實做自定的Serialize動作請直接參考MSDN的範例 在這邊要討論的是小弟不久前遇到的一個問題,首先把焦點放到之前提過的 [Serializable]這個屬性,由於這個屬性不具備繼承的能力( AttributeUsageAttribute(...,Inherited = false) ) 所以下面的程式碼會有問題 class MyBase { .... } [Serializable] class MyDerived : MyBase, ISerializable { public MyDerived(){} public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { ....... //處理MyDerived的Serialize動作 base.GateObjectData(info,context); //處理base的serialize ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 這一行會丟出SerializationException因為base沒有[Serializable] } protected MyDerived(SerializationInfo info, StreamingContext context) : base(info,context) ^^^^^^^^^throw Exception { ... //處理deserialize的動作 } } 有幾種方法可以解決 1.把程式碼中串聯到base的serialize動作拿掉 (base.GateObjectData(info,context); or base(info,context)) 但是假如哪天base又變成需要serialize是不是我們又要把這些被拿掉的程式碼 加回去? 2.將base也標上[Serializable] 問題是第一如果base真的不需要serialize這顯然會混淆其他的工程師。 第二 假如base我們沒有source code怎辦?叫提供base的廠商給我們加上 後再寄來? 上面兩種解法都會造成我門開發的class和base再處理serialize上的偶合(coupling) 也就是我們沒有辦法在base變更serialize的支援時不改變繼承體系其他的class程式。 程式有越多的偶合就越難維護,這當然要避免,這邊提供一個例子 class GenericBaseSerialize { public static void SerializeBase(SerializationInfo info, StreamingContext context, object obj) { Type baseType = obj.GetType().BaseType; //當baseType為object時結束deserialize while(baseType != typeof(object)) { BindingFlag flag = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public; //取得所有base type 的 Fields FieldInfo[] fields = baseType.GetFields(flag); foreach (FieldInfo field in fields) { if(field.IsNotSerialized) { //field不需要serialize繼續下一個field continue; } string sToken = type.Name + field.Name; info.AddValue(sToken, field.GetValue(obj)); } //繼續處理base type baseType = baseType.BastType; } } public static void DeSerializeBase(SerializationInfo info, StreamingContext context, object obj) { Type baseType = obj.GetType().BaseType; //當baseType為object時結束deserialize while(baseType != typeof(object)) { BindingFlag flag = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public; //取得所有base type 的 Fields FieldInfo[] fields = baseType.GetFields(flag); foreach (FieldInfo field in fields) { if(field.IsNotSerialized) { //field不需要serialize繼續下一個field continue; } string sToken = type.Name + field.Name; //取出field的值(deserialize) object value = info.GetValue(sToken,field.FieldType); //將取出的值設定到obj中的field field.SetValue(obj, value); } //繼續處理base type baseType = baseType.BastType; } } } [Serializable] class MyDerived : MyBase, ISerializable { public MyDerived(){} public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { ....... //處理MyDerived的Serialize動作 //處理base的serialize動作 GenericBaseSerialize.SerializeBase(info,context,this); } protected MyDerived(SerializationInfo info, StreamingContext context) { ... //處理deserialize的動作 //處理base的serialize動作 GenericBaseSerialize.DeSerializeBase(info,context,this); } } 完全不用再花心力去管base是否有支援[Serializable]了。 不過這個做法有一個缺點就是Reflection的動作實在是很慢,大量物件還是盡量避免 ...畢竟彈性和效率總是兩難全... --



※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.229.16.186
1F:推 seagal:頭推 p兄的文章每次都很有深度 140.109.73.177 06/22
2F:推 sheauren:不考慮空間問題 我是都把object轉成xml儲存 140.125.251.33 06/22
3F:→ psvsps2:小弟說的大量物件是可能程式中會頻繁建立一個 211.75.23.122 06/22
4F:→ psvsps2:物件非常多次,如果這種情形每次serialize時 211.75.23.122 06/22
5F:→ psvsps2:都用上面方法對效率影響頗大 211.75.23.122 06/22
6F:推 sheauren:之前是因為傳遞WebService的時候使用到:D 140.125.251.33 06/23







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:Gossiping站內搜尋

TOP