.NET组件程序设计 第9章 序列化和持久化

来源:互联网 发布:nginx 跳转到指定域名 编辑:程序博客网 时间:2024/05/17 04:24

序列化和持久化:

描述对象状态以某种形式存储到文件,以及后来的恢复该对象状态。

 

Serializable属性:

默认,用户定义类型(类,结构)不可序列化,需要显示用[Serializable]特性修饰自定义类型。

 

不可序列化成员:

当一个类可序列化,.NET检查其下所有成员变量都可以序列化。当序列化时,.NET发现不可序列化成员会抛出异常。

对不可序列化的成员,应该用[NonSerialized]特性修饰,这样在序列化时会忽略跳过该成员。在反序列化时,会将不可序列化对象先初始化为默认值,再用自定义步骤将之初始化为正确值。

using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.IO;[Serializable]public class MyClass : IDeserializationCallback{    //该字段将不被序列化    [NonSerialized]    private int m_Number = 1;    #region IDeserializationCallback 成员    //在反序列化后调用,初始未序列化字段    public virtual void OnDeserialization(object sender)    {        //输出:0        Console.WriteLine(m_Number);        m_Number = 3;        //输出:3        Console.WriteLine(m_Number);    }    #endregion}static void Main(string[] args){    #region 序列化    //MyClass mc = new MyClass();    //IFormatter formatter = new BinaryFormatter();    //Stream stream = new FileStream(@"D:\66_Code\Se\obj.bin", FileMode.Create, FileAccess.Write);    //using (stream)    //{    //    formatter.Serialize(stream, mc);    //}    #endregion    #region 反序列化    MyClass obj;    IFormatter formatter = new BinaryFormatter();    Stream stream = new FileStream(@"D:\66_Code\Se\obj.bin", FileMode.Open, FileAccess.Read);    using (stream)    {        obj = (MyClass)formatter.Deserialize(stream);    }    #endregion    Console.Read();}

 

委托和序列化:

//委托成员变量应标记为不可序列化[NonSerializable]private EventHandler m_MyEvent;//对于事件,要加上field属性限定[field:NonSerializable]private event EventHandler m_MyEvent;


序列化格式器:

格式器是一个实现 IFormatter接口的对象。

1.二进制格式器(BinaryFormatter)

2.SOAP格式器(SoapFormatter)

using System.Runtime.Serialization.Formatters.Soap;#region 序列化//MyClass mc = new MyClass();//IFormatter formatter = new SoapFormatter();//Stream stream = new FileStream(@"D:\66_Code\Se\obj.xml", FileMode.Create, FileAccess.Write);//using (stream)//{//    formatter.Serialize(stream, mc);//}#endregion#region 反序列化MyClass obj;IFormatter formatter = new SoapFormatter();Stream stream = new FileStream(@"D:\66_Code\Se\obj.xml", FileMode.Open, FileAccess.Read);using (stream){    obj = (MyClass)formatter.Deserialize(stream);}#endregion


XML序列化(XmlSerializer):

为了面向因特网与其他平台交换数据。.NET序列化基于组件,面向应用程序和交互对象。

using System.Xml.Serialization;#region 序列化//MyClass mc = new MyClass();//XmlSerializer xml = new XmlSerializer(typeof(MyClass));//Stream stream = new FileStream(@"D:\66_Code\Se\obj.xml", FileMode.Create, FileAccess.Write);//using (stream)//{//    xml.Serialize(stream, mc);//}#endregion#region 反序列化MyClass obj;XmlSerializer xml = new XmlSerializer(typeof(MyClass));Stream stream = new FileStream(@"D:\66_Code\Se\obj.xml", FileMode.Open, FileAccess.Read);using (stream){    obj = (MyClass)xml.Deserialize(stream);}#endregion


序列化事件:

当序列化或反序列化发生时,.NET支持在类上调用自定义方法处理。

[Serializable]public class MyClass{    //序列化事件(当前类必须标记为可序列化,且只有BinaryFormatter,SoapFormatter调用序列化,反序列化才有效)    //除了.NET应没有其他程序能调用序列化事件,建议设为私有    [OnSerializing]    private void OnSerializing(StreamingContext context)    {        Console.WriteLine("在序列化开始前调用");    }    [OnSerialized]    private void OnSerialized(StreamingContext context)    {        Console.WriteLine("在序列化后调用");    }    [OnDeserializing]    private void OnDeserializing(StreamingContext context)    {        Console.WriteLine("在反序列化前调用");    }    //可代替OnDeserialization()方法,初始化未序列化字段    [OnDeserialized]    private void OnDeserialized(StreamingContext context)    {        Console.WriteLine("在反序列化后及OnDeserialization()方法后调用");    }}


克隆可序列化对象(利用类存流):

//克隆可序列化对象public static T Clone<T>(T obj){    //检查当前类型是否可序列化    if (typeof(T).IsSerializable)    {        IFormatter formatter = new BinaryFormatter();        //将对象,序列化到内存流中保存再反序列化,完成深层次克隆对象        Stream stream = new MemoryStream();        using (stream)        {            formatter.Serialize(stream, obj);            stream.Seek(0, SeekOrigin.Begin);            T clone = (T)formatter.Deserialize(stream);            return clone;        }    }    throw new Exception();}


序列化多个对象:

[Serializable]public class MyClass{}[Serializable]public class MyOtherClass{}class Program{    static void Main(string[] args)    {        MyClass mc = new MyClass();        MyOtherClass moc = new MyOtherClass();        IFormatter formatter = new BinaryFormatter();        //将不同对象使用同一流序列化的同一文件中        Stream stream = new FileStream(@"D:\66_Code\Se\All.bin", FileMode.Create, FileAccess.Write);        using (stream)        {            formatter.Serialize(stream, mc);            formatter.Serialize(stream, moc);        }        mc = null;        moc = null;        //从同一文件反序列化为不同对象(注意顺序!)        stream = new FileStream(@"D:\66_Code\Se\All.bin", FileMode.Open, FileAccess.Read);        using (stream)        {            mc = (MyClass)formatter.Deserialize(stream);            moc = (MyOtherClass)formatter.Deserialize(stream);        }        Console.Read();    }}


自定义序列化(通过实现ISerializable接口):

//实现ISerializable接口的类必用Serializable特性修饰,否则.NET将忽略该接口[Serializable]public class MyClass<T> : ISerializable{    private string m_String = "LULU";    //此处无法保证T的类型是可序列化的    private T m_Value;    #region 构造函数    //为支持相匹配自定义反序列化,必须提供一反序列化构造函数    //应将该构函始终定义为受保护,防止客户端调用    protected MyClass(SerializationInfo info, StreamingContext context)    {        //反序列化时,将加密后的值解密还原为正确值        m_String = info.GetString("m_String").ToUpper();        //泛型        m_Value = (T)info.GetValue("m_Value", typeof(T));    }    //定义静态构造函数,实现在使用该类前,执行一次运行时检查    //可用此技巧进行其他约束性检查    static MyClass()    {        if(typeof(T).IsSerializable == false)        {            throw new SerializationException("类型不可序列化!");        }    }    public MyClass()    { }    #endregion    #region ISerializable 成员    //序列化对象时,.NET会先检查是否可序列化,再检查是否实现ISerializable接口    //实现该接口,就调用GetObjectData()获取对象状态    public void GetObjectData(SerializationInfo info, StreamingContext context)    {        //可以按照自定义方式提供值(实现加密之类,避免暴露真实值)        info.AddValue("m_String", m_String.ToLower());        //泛型        info.AddValue("m_Value", m_Value, typeof(T));    }    #endregion}


序列化和类层次结构:

对一个类使用Serializable特性,只影响该类,不会导致派生类可序列化。

原创粉丝点击