.Net 序列化问题 之[未找到反序列化“XXX”类型对象的构造函数]

 序列化在开发的过程中重要性不言而喻。使用场景一般为:

1、应用程序的状态(对象图)保存到文件系统或数据库中。可在需要的时候对这些对象进行恢复。如ASP.NET通过序列化和反序列化来保存和恢复会话状态。

2、对象的备份。案件对某些对象的生成极为困难,如需要大量的计算、IO等,但是结果比较恒定,我们可以把这些对象保存下来。

3、程序可视化对象的复制与粘贴。如WinForm和WPF的对象的复制和粘贴。

4、网络间对象通信,进程间通信等。

5、对象的加密和解密。

  一般来说如果继承基类需要基类本身可序列化,如作为万物的Object就是可序列化的。对于不序列化的对象我们可以通过"重写程序集和/或类型"来使不可序列化的对象变得可序列化。

     

     序列化常识

1、格式化器参考对每个对象的类型进行描述元数据,从而了解如何序列化完整的对象图
2、格式化器针对循环引用会智能判断从而只生成一次
3、序列化和反序列化使用反射来获取对象的信息和为对象赋值。
4、多个对象可序列化到一个流中(类型的全名和类型的定义程序集名称会被写入流)
5、格式化器使用Assembly.Load来将需要反序列化对象的程序集加载到AppDomain中
6、格式化器的工作过程
System.Runtime.Serialization.FormatterServices来序列化类型实例
序列化过程:
step1:public static MemberInfo[] GetSerializableMembers(Type type,StreamingContext context);
step2:public static Object[] GetObjectData(Object obj,MemberInfo[] members);
step3:格式化器将应用程序集标识和类型的完整名称写入流中
step4:格式化器遍历两个数组中的元素,将每个成员的名称和值写入流中。
反序列化过程:
step1:根据程序集标识和类型的完整名称来获取对象的类型信息,如没有会使用Assembly.Load进行加载
public static Type GetTypeFromAssembly(Assembly assem,String name);
step2:为对象分配内存,并不为对象调用构造器。对象的所有字段都被初始化null或0
public static Object GetUninitializedObject(Type type);
step3:获取需要反序列化的数组
public static MemberInfo[] GetSerializableMembers(Type type,StreamingContext context);
step4:格式化器需要流中的数据创建一个Object对象数组
step5:为对象分配值
pubilc static Objevt PopulateObjectMembers(Object obj,Memberinfo[] members,Object[] data);
7、

建议:
1、格式化器出于性能考虑不会验证对象图中所有的对象都能序列化,所以可以会出现流中会有部分已经序列化的对象。
所以最好先把对象序列化到MemoryStream,成功之后再写入目标流(文件、网络中)
2、枚举和委托总是可序列化的

控制序列化和反序列化:
1、实现了ISerializable接口,格式化器会忽略所有定制attribute,改为构造一个新的System.Runtime.SerializationInfo对象。
可以通过ISerializable的GetObjectData来自定义序列化的方法。
特殊的反序列化构造器(这是ISeriablizable需要的)否则会报上述错误(如标题所示的错误)
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
protected 类名(SerializationInfo info,StreamContext context)
{}

  

   

 后记:本来想记录一下这个问题产生的原因,后来确写成了读书笔记。(参见CLR via C# 第三版)

原文地址:https://www.cnblogs.com/wangn/p/3559997.html