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灯, 水草

请输入看板名称,例如:Soft_Job站内搜寻

TOP