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

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

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

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

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

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

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

IDeserializationCallback接口

using System;
using System.Runtime.InteropServices;

namespace System.Runtime.Serialization
{
    // 摘要:
    //     指示在完成整个对象图形的反序列化时通知类。
    [ComVisible(true)]
    public interface IDeserializationCallback
    {
        // 摘要:
        //     在整个对象图形已经反序列化时运行。
        //
        // 参数:
        //   sender:
        //     开始回调的对象。当前未实现该参数的功能。
        void OnDeserialization(object sender);
    }
}

 

IDeserializationCallback接口是反序列化时会执行的接口,接口里面只有一个OnDeserialization方法,系统在反序列化的时候会检查待序列化对象是否实现了IDeserializationCallback接口,如果实现了,那么系统就调用该接口中的OnDeserialization方法。

[王清培版权所有,转载请给出署名]

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace ConsoleApplication1.序列化和持久化
{
    [Serializable]
    public class MyClass : IDeserializationCallback
    {
        public MyClass() { }
        public string number = "MyClass状态";
        [field: NonSerialized]//事件必须用field进行修饰
        public event EventHandler Event;
        #region IDeserializationCallback 成员
        public void OnDeserialization(object sender)
        {
        }
        #endregion)
    }
}

 

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

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Runtime.Serialization.Formatters;
using System.IO;

namespace ConsoleApplication1.序列化和持久化
{
    public static class Program
    {
        public static void Main()
        {

            SoapFormatter formatter = new SoapFormatter();

            Stream stream = new FileStream("obj.xml", FileMode.Create, FileAccess.Write);
            using (stream)
            {
                MyClass myclass = new MyClass();
                myclass.Event += new EventHandler(myclass_Event);
                formatter.Serialize(stream, myclass);
            }

            Stream stream1 = new FileStream("obj.xml", FileMode.Open, FileAccess.Read);
            using (stream1)
            {
                MyClass myclass = formatter.Deserialize(stream1) as MyClass;
            }

        }

        static void myclass_Event(object sender, EventArgs e)
        {

        }
    }
}

 

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

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace ConsoleApplication1.序列化和持久化
{
    [Serializable]
    public class MyClass : IDeserializationCallback, ISerializable
    {
        public MyClass() { }
        public string number = "MyClass状态";

        [field: NonSerialized]//事件必须用field进行修饰
        public event EventHandler Event;

        #region IDeserializationCallback 成员

        public void OnDeserialization(object sender)
        {

        }

        #endregion)

    }
}

 

序列化生命周期事件

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

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

        [OnSerializing]
        void OnSerializing(StreamingContext context)
        {

        }
        [OnSerialized]
        void OnSerialized(StreamingContext context)
        {

        }
        [OnDeserializing]
        void OnDeSerializing(StreamingContext context)
        {

        }
        [OnDeserialized]
        void OnDeserizlized(StreamingContext context)
        {

        }

 

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

ISerializable接口

using System;
using System.Runtime.InteropServices;

namespace System.Runtime.Serialization
{
    // 摘要:
    //     允许对象控制其自己的序列化和反序列化过程。
    [ComVisible(true)]
    public interface ISerializable
    {
        // 摘要:
        //     使用将目标对象序列化所需的数据填充 System.Runtime.Serialization.SerializationInfo。
        //
        // 参数:
        //   info:
        //     要填充数据的 System.Runtime.Serialization.SerializationInfo。
        //
        //   context:
        //     此序列化的目标(请参见 System.Runtime.Serialization.StreamingContext)。
        //
        // 异常:
        //   System.Security.SecurityException:
        //     调用方没有所要求的权限。
        void GetObjectData(SerializationInfo info, StreamingContext context);
    }
}

 

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

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

 public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("number", "手动添加的状态");
        }
        #endregion

        //反序列化构造函数
        protected MyClass(SerializationInfo info, StreamingContext context)
        {
            this.number = (string)info.GetValue("number", typeof(string));
        }

 

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

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

protected MyClass(SerializationInfo info, StreamingContext context)

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

时间: 2024-10-01 21:50:11

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

.NET简谈组件程序设计之(初识序列化、持久化)

 今天我们来学习在组件开发中经常用到的也是比较重要的技术"序列化". 序列化这个名词对初学者来说不太容易理解,有点抽象.我们还是用传统的分词解释吧,肯定能搞懂它的用意是什么. 解释:数学上,序列是被排成一列的对象(或事件):这样,每个元素不是在其他元素之前,就是在其他元素之后.这里,元素之间的顺序非常重要. 那么我们对照这样的解释来分析一下我们程序中的序列化什么意思.都知道对象的状态是在内存中实时存着的,对象的状态在初始化的时候是通过系统分配的,在后期的程序运行过程中可能对它进行过一些

.NET简谈组件程序设计之(初识NetRemoting)

在本人的".NET简谈组件程序设计之(初识远程调用)  "一文中,我们了解到什么是远程调用或者说在.NET平台上远程调用是什么样子的,可能和偏低层(Socket\Rpc)的远程调用有点距离.这只是系统为我们封装了假象而已,看不见不代表没有这逻辑,是为我们减轻了劳动负担.[王清培版权所有,转载请给出署名] 这篇文章我们来简单的了解一下在.NET平台上有一个强有力的远程调用武器,也是上一篇文章中我一笔带过的远程英雄.NetRemoting. 其实在.NET平台里面到处都能看见Remotin

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

我们继续学习.NET多线程技术,这篇文章的内容可能有点复杂.在打破常理之后,换一种新的思考模型最为头疼.这篇文章里面会涉及到一些不太常见的概念,比如:上下文.同步域等等.我也是最近才接触这些关于组件编程方面的高深技术,大家一起学习,再大的困难也是有时间限制的,只要我们坚持. 在本人的上一篇文章".NET简谈组件程序设计之(多线程与并发管理一)"中,只是初步的带领我们学习一下关于多线程的一些基本的原理,包括线程切换,线程的开始.执行.等待.结束. 这篇文章的重点是学习关于线程的同步.互斥

.NET简谈组件程序设计之(初识.NET线程Thread)

由于多线程的内容比较多我会用几篇文章来讲解. 多线程在我们日常开发过程中用的很多,上一篇".NET简谈组件程序设计之(异步委托) "详细的讲解了基于委托的多线程使用,委托是基于后台线程池的原理,这篇文章将主要介绍直接使用Thread对象来实现多线程. 当然使用Thread没有使用Delegate那么容易,毕竟多线程跟异步调用是两个相差很大的技术方向,我也是略懂点皮毛,在此献丑给大家,如有讲的不对的地方还请指出.[王清培版权所有,转载请给出署名] 我们先来理解几个概念,以方便我们学习.

.NET简谈组件程序设计之(初识远程调用)

在.NET1.0版本出来的时候,要想进行远程调用基本上都是通过WebService的方式.而随着.NET2.0版本的出现,我们可以通过一个更加方便且高扩展性的框架来进行编写远程调用的程序,也就是我们都比较熟悉的.NetRemoting. 网上对.NetRemoting技术讲解的文章不计其数,但是很少有一本比较全面的.系统的学习书籍.我们都是从哪些零散的知识里慢慢摸索,效果不太理想. 今天我也来简单的介绍一下我理解的Remoting.不仔细研究一下还真不知道它的厉害,完全的托管平台.高扩展性.灵活

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

在上一篇文章".NET简谈组件程序设计之(上下文与同步域)"中,我们学习了关于一些上下文和同步域的概念,可以利用这两个技术来进行自动同步. 今天我们主要学习怎么手动来执行同步,能从更小的粒度进行封锁,以达到最大程度的吞吐量.[王清培版权所有,转载请给出署名] 我们知道线程是进程的运行实体,进程是资源分配单位,而线程是执行单位.照书上所说,线程是程序的执行路径,当我们分配一个线程的时候,要确定线程的执行路径是什么,也就是代码中的ThreadStart委托所指向的入口点方法. 一旦我们手动

.NET简谈组件程序设计之(delegate与event关系)

 本人最近一段时间在学习关于.NET组件编程方面的技术,在学习过程中确实有很多好的东西需要与大家分享.[王清培版权所有,转载请给出署名] 关于什么叫组件编程,其实就是利用.NET来开发基于组件模型的程序,面向组件编程而非面向对象编程,这是一个高度,没有很长时间的学习与磨练 是体会不到这个感觉的.我们现在的开发思想应该是以面向对象为主的,但是如何提升这个高度,只有慢慢的学习了. 其实面向组件编程包含了面向对象编程思想,将一组功能独立的封装起来供以后重复使用,但是在开发组件的过程中需要使用到面向对象

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

在本人的上一篇文章中只是简单的介绍了一下.NETRemoting的一般概念和基本的使用.这篇文章我想通过自己的学习和理解将对.NETRemoting的整体的一个框架进行通俗的讲解,其中最重要的就是信道(管道)处理模型思想,这里面蕴含了很多的设计原理.[王清培版权所有,转载请给出署名].NETRemoting远程处理架构是一个半成品,是.NET给我们的扩展框架,要想用于商业项目必须进行一些安全.性能方面的控制.要想进行一定深度的扩展那就要必须了解它的整体结构,各个点之间的关系才能很好的控制它. 网

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

最近在苦学.NET底层框架模型,发现.NET深入真的不是一般的难,不开源.没有相关系统的官方的书籍做学习资料,只能零散的看MSDN.要想摸熟.NET的模型真的并非易事.慢慢来吧.[王清培版权所有,转载请给出署名] .NET应用程序域(AppDomain)是我们所有.NET应用程序的逻辑宿主容器.初次接触会感觉到AppDomain离我们日常开发比较远,不常用到.其实是我们很少接触一些复杂而底层的系统结构.在日常的开发中,我们多数是基于数据库的管理信息系统(MIS),做增.删.改.查的操作.我始终认