在本人的上一篇文章“.NET简谈组件程序设计之(初识序列化、持久化) ”中,我们基本上了解了什么叫序列化和持久化。通过系统为我们提供的服务,我们可以很方便的进行二进制序列化、SOAP协议序列化。

今天这篇文章是来讲解怎么运用一些高级的功能,在序列化、反序列化过程中进行一些控制。[王清培版权所有,转载请给出署名]

这里穿插一句题外话:其实在我们自己编写组件的时候真的有好多东西可以借鉴.NET平台的一些优点,它的功能都不是死的,可以订阅、可以切入,在我们编写组件的时候,我们其实也要好好考虑一些高级的特性。

上面这段话其实是为了铺垫用的,意思是说序列化组件在它工作的时候我们可以“参合”进去。

IFormatter格式器接口在工作的时候会去检查要序列化的对象是否用Serializable特性进行了标记,如果有,那么就进行深度递归遍历或者广度递归遍历所有成员,如果内部成员被NonSerialized禁止序列化特性标记,那么IFormatter将跳过该成员。在对象的内部所有的成员如果没有被禁止序列化,那么都会经过序列化工程,所以我们很难保证在特殊的对象上能否递归遍历序列化成功。

很典型的对象就是event事件对象,在订阅列表中我们不能保证所有的订阅者都能够被序列化,但是我们又想在反序列化的时候能初始化一些数据。

IDeserializationCallback接口

  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace System.Runtime.Serialization
  4. {
  5. // 摘要:
  6. //     指示在完成整个对象图形的反序列化时通知类。
  7. [ComVisible(true)]
  8. public interface IDeserializationCallback
  9. {
  10. // 摘要:
  11. //     在整个对象图形已经反序列化时运行。
  12. //
  13. // 参数:
  14. //   sender:
  15. //     开始回调的对象。当前未实现该参数的功能。
  16. void OnDeserialization(object sender);
  17. }
  18. }

IDeserializationCallback接口是反序列化时会执行的接口,接口里面只有一个OnDeserialization方法,系统在反序列化的时候会检查待序列化对象是否实现了IDeserializationCallback接口,如果实现了,那么系统就调用该接口中的OnDeserialization方法。[王清培版权所有,转载请给出署名]

那么这个方法我们有何用呢,我们来看代码;

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.Serialization;
  5. namespace ConsoleApplication1.序列化和持久化
  6. {
  7. [Serializable]
  8. public class MyClass : IDeserializationCallback
  9. {
  10. public MyClass() { }
  11. public string number = "MyClass状态";
  12. [field: NonSerialized]//事件必须用field进行修饰
  13. public event EventHandler Event;
  14. #region IDeserializationCallback 成员
  15. public void OnDeserialization(object sender)
  16. {
  17. }
  18. #endregion)
  19. }
  20. }

MyClass类中有一个Event事件对象,我们在它上面加了禁止序列化特性,前面的field是用来把event对象也当成字段来看待,因为NonSerialized特性只能用在field字段上。

我们实现IDeserializationCallback接口,这个接口的方法会再每次反序列化的时候执行。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.Serialization;
  5. using System.Runtime.Serialization.Formatters.Binary;
  6. using System.Runtime.Serialization.Formatters.Soap;
  7. using System.Runtime.Serialization.Formatters;
  8. using System.IO;
  9. namespace ConsoleApplication1.序列化和持久化
  10. {
  11. public static class Program
  12. {
  13. public static void Main()
  14. {
  15. SoapFormatter formatter = new SoapFormatter();
  16. Stream stream = new FileStream("obj.xml", FileMode.Create, FileAccess.Write);
  17. using (stream)
  18. {
  19. MyClass myclass = new MyClass();
  20. myclass.Event += new EventHandler(myclass_Event);
  21. formatter.Serialize(stream, myclass);
  22. }
  23. Stream stream1 = new FileStream("obj.xml", FileMode.Open, FileAccess.Read);
  24. using (stream1)
  25. {
  26. MyClass myclass = formatter.Deserialize(stream1) as MyClass;
  27. }
  28. }
  29. static void myclass_Event(object sender, EventArgs e)
  30. {
  31. }
  32. }
  33. }

我们在MyClass类中订阅了Event事件,如果我没有在MyClass类中的Event事件上加上禁止序列化特性,那么执行序列化的时候肯定是回报错的。

如果我们需要再对象MyClass存在的时候就需要有一个事件订阅者存在,比如对象内部的日志记录、消息发送等。我们就可以在OnDeserialization方法中进行处理。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.Serialization;
  5. namespace ConsoleApplication1.序列化和持久化
  6. {
  7. [Serializable]
  8. public class MyClass : IDeserializationCallback
  9. {
  10. public MyClass() { }
  11. public string number = "MyClass状态";
  12. [field: NonSerialized]//事件必须用field进行修饰
  13. public event EventHandler Event;
  14. #region IDeserializationCallback 成员
  15. public void OnDeserialization(object sender)
  16. {
  17. Event += new EventHandler(MyClass_Event);
  18. }
  19. void MyClass_Event(object sender, EventArgs e)
  20. {
  21. //对象内部处理
  22. }
  23. #endregion)
  24. }
  25. }

序列化生命周期事件

在序列化和反序列化的过程中,系统会经历几个过程。大致分为下列四种,

序列化前(OnSerializing)、序列化后(OnSerialized)、反序列化前(OnDeserializing)、反序列化后(OnDeserialized),然后系统给我们留了入口,我们可以通过参与这几个方法来进行一些过程控制。请看代码;

  1. [OnSerializing]
  2. void OnSerializing(StreamingContext context)
  3. {
  4. }
  5. [OnSerialized]
  6. void OnSerialized(StreamingContext context)
  7. {
  8. }
  9. [OnDeserializing]
  10. void OnDeSerializing(StreamingContext context)
  11. {
  12. }
  13. [OnDeserialized]
  14. void OnDeserizlized(StreamingContext context)
  15. {
  16. }

这几个特性就是用来标记序列化组件的过程的,系统会在处理的时候分别调用这几个方法,我们可以在几个方法中进行过程控制。StreamingContext是序列化流的对象,我们可以获取到序列化流的目标。

ISerializable接口

  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace System.Runtime.Serialization
  4. {
  5. // 摘要:
  6. //     允许对象控制其自己的序列化和反序列化过程。
  7. [ComVisible(true)]
  8. public interface ISerializable
  9. {
  10. // 摘要:
  11. //     使用将目标对象序列化所需的数据填充 System.Runtime.Serialization.SerializationInfo。
  12. //
  13. // 参数:
  14. //   info:
  15. //     要填充数据的 System.Runtime.Serialization.SerializationInfo。
  16. //
  17. //   context:
  18. //     此序列化的目标(请参见 System.Runtime.Serialization.StreamingContext)。
  19. //
  20. // 异常:
  21. //   System.Security.SecurityException:
  22. //     调用方没有所要求的权限。
  23. void GetObjectData(SerializationInfo info, StreamingContext context);
  24. }
  25. }

如果我们想更进一步的控制序列化和反序列化过程,那么我们就来实现ISerializable接口,通过这个接口我们基本上能控制序列化和反序列化的所有数据。

我们在MyClass类中加上这些代码。

  1. #region ISerializable 成员
  2. public void GetObjectData(SerializationInfo info, StreamingContext context)
  3. {
  4. info.AddValue("number", "手动添加的状态");
  5. }
  6. #endregion
  7. //反序列化构造函数
  8. protected MyClass(SerializationInfo info, StreamingContext context)
  9. {
  10. this.number = (string)info.GetValue("number", typeof(string));
  11. }

我们实现了ISerializable接口,里面只有一个方法GetObjectData,这个方法我想是系统要调用的,是用来获取序列化数据对的,我们通过Serializationinfo对象来进行设置。其实SerializationInfo是对StreamingContext对象的包装,主要的目的就是用来进行数据的设置的。StreamingContext是序列化流的引用,最后是要将这些数据写入Stream中的。

有一个至关重要的地方就是,在系统进行反序列化的时候不会调用Serializable特性标记的对象的默认构造函数,因为系统也不确定在构造函数是否能恢复对象的所有的数据,因为在序列化的时候可能过滤了部分NonSerializable标记对象。所以系统会调用自己规定的以个重载构造函数,就是我上面所写的:

protected MyClass(SerializationInfo info, StreamingContext context)

系统通过Serializationinfo和StreamingContext两个对象来恢复当初序列化到StreamContext中的数据。[王清培版权所有,转载请给出署名]

本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/658257,如需转载请自行联系原作者

.NET简谈组件程序设计之(渗入序列化过程)相关推荐

  1. .NET简谈组件程序设计之(手动同步)

    在上一篇文章".NET简谈组件程序设计之(上下文与同步域) "中,我们学习了关于一些上下文和同步域的概念,可以利用这两个技术来进行自动同步. 今天我们主要学习怎么手动来执行同步,能 ...

  2. .NET简谈组件程序设计之(上下文与同步域)

    我们继续学习.NET多线程技术,这篇文章的内容可能有点复杂.在打破常理之后,换一种新的思考模型最为头疼.这篇文章里面会涉及到一些不太常见的概念,比如:上下文.同步域等等.我也是最近才接触这些关于组件编 ...

  3. .NET简谈组件程序设计之(详解NetRemoting结构)

    在本人的上一篇文章中只是简单的介绍了一下.NETRemoting的一般概念和基本的使用.这篇文章我想通过自己的学习和理解将对.NETRemoting的整体的一个框架进行通俗的讲解,其中最重要的就是信道 ...

  4. .NET简谈组件程序设计之(AppDomain应用程序域)

    最近在苦学.NET底层框架模型,发现.NET深入真的不是一般的难,不开源.没有相关系统的官方的书籍做学习资料,只能零散的看MSDN.要想摸熟.NET的模型真的并非易事.慢慢来吧.[王清培版权所有,转载 ...

  5. .NET简谈组件程序设计之(异步委托)

    说到委托我想大家基本上都用过的,今天这篇文章就来讲解关于委托的异步奥秘. 在我们正常使用的时候很少会去用异步委托技术来提高代码效率.委托的好处就是能对方法进行面向对象的封装,随意传递.在任何组件客户代 ...

  6. .NET简谈事务、分布式事务处理

    在本人的 " .NET简谈事务本质论"一文中我们从整体上了解了事务模型,在我们脑子里能有一个全局的事务处理结构,消除对数据库事务的依赖理解,重新认识事务编程模型. 今天这篇文章我们 ...

  7. iOS应用架构谈 组件化方案

    简述 前几天的一个晚上在infoQ的微信群里,来自蘑菇街的Limboy做了一个分享,讲了蘑菇街的组件化之路.我不认为这条组件化之路蘑菇街走对了.分享后我私聊了Limboy,Limboy似乎也明白了问题 ...

  8. 浅谈单片机程序设计中的“分层思想”!

    浅谈单片机程序设计中的"分层思想",并不是什么神秘的东西,事实上很多做项目的工程师本身自己也会在用.看了不少帖子都发现没有提及这个东西,然而分层结构确是很有用的东西,参透后会有一种 ...

  9. php谈谈你对分布式的理解,简谈关于对分布式处理的理解

    原标题:简谈关于对分布式处理的理解 最近这段时间一直在看分布式有关的东西,但是关于分布式自己还是不能很好的理解,所以本文对分布式基础概念进行下学习. 分布式处理 首先先了解一下分布式处理,分布式处理和 ...

最新文章

  1. 学python好不好-学历低可以学python吗?好不好就业?
  2. [O(N)的我不会]树网的核
  3. python访问数据库日志文件_python利用inotify实现把nginx日志实时写入数据库
  4. Lua的upvalue和闭包
  5. c#字符型转化为asc_wap站 utf-8与 gb2312字符编码的转化函数
  6. 论文浅尝 | 如何利用外部知识提高预训练模型在阅读理解任务中的性能
  7. 2019年中国IaaS公有云市场排名及份额出炉
  8. POI (Apache POI)
  9. 如何设置基于Windows 2000/2003/20008平台下的智能域名服务器
  10. 前端事件绑定知识点(面试常考)
  11. CSS3 background-clip属性
  12. 你最缺钱的时候是怎么度过的?
  13. dism 分割镜像_UEFI安装win10 1809系统,拆分Windows 映像大于4G文件install.wim的官方教程(亲测完美)...
  14. python利用reportlab打印图文并茂内容
  15. 腾讯云轻量型服务器与云服务器的区别
  16. 内网KDC服务器开放在哪个端口,针对kerbores的攻击有哪些?
  17. 【YOLOX 论文+源码解读】YOLOX: Exceeding YOLO Series in 2021
  18. 前端基于excljs导出xlsx时图片资源的处理及踩坑实录
  19. STC12系列单片机的AUXR辅助寄存器
  20. 船长就是法律!古代海盗残酷刑罚

热门文章

  1. LeetCode 724. Find Pivot Index
  2. 蓝桥杯 ADV-203 算法提高 8皇后·改(八皇后问题)
  3. html数据插入到数据库,将数据插入到数据库中:text和html格式
  4. python colorbar位置大小调整_python - matplotlib相邻子图:添加colorbar更改子图的大小 - 堆栈内存溢出...
  5. JDBC连接数据库教程,以postgreSQL为例
  6. Eclipse console 编码设置
  7. 并发编程之——写锁源码分析
  8. 使用内部(com.android.internal)和隐藏(@hide)API手记
  9. 一个数据科学家对商学院的建议
  10. Hadoop2.x介绍与源代码编译