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

本文探讨了.NET中的序列化和持久化,包括如何使用Serializable属性标记可序列化类型,处理不可序列化的成员,以及委托与序列化的交互。文章还介绍了二进制和SOAP格式器,重点讲解了XML序列化在跨平台数据交换中的作用。同时,提到了序列化事件和如何通过ISerializable接口实现自定义序列化,特别是面对类层次结构时的处理策略。
摘要由CSDN通过智能技术生成

序列化和持久化:

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

 

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特性,只影响该类,不会导致派生类可序列化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值