• C#对象序列化(3)


    C#对象序列化(3)
    作者: 日期:2009-3-14 23:43:39 出处:淘特网
    using System;
    ……………………………………………
    //导入必要的命名空间
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Runtime.Serialization;
    using System.IO;
    namespace CustomSerialize
    {
    public partial class form1 : Form
    {
    //声明string类型变量,用于存储用户确认的路径
    string fn;       
    public form1()
    {
    InitializeComponent();
    }
             private void form1_Load(object sender, EventArgs e)
    {
    //窗体载入时,下面两个GroupBox容器控件不可用
    this.groupBox2.Enabled = false;
    this.groupBox3.Enabled = false;
    }
             private void PathBtn_Click(object sender, EventArgs e)
    {
    //获取PathTxt的Text属性值,并赋值给fn变量和PathLabel的Text属性值
    fn = PathTxt.Text;
    PathLabel.Text = fn;
    //下面两个GroupBox容器控件可用
    this.groupBox1.Enabled = false;
    this.groupBox2.Enabled = true;
    //第1个GroupBox容器控件可用
    this.groupBox3.Enabled = true;
    }
             private void SerBtn_Click(object sender, EventArgs e)
    {
    //创建Details类对象Dt
    Details Dt = new Details();
    //将两个文本框内容复制给Dt的两个属性
    Dt.Name = nametxt.Text;
    Dt.NickName = nicknametxt.Text;
    //创建IFormatter接口引用,来自于BinaryFormatter类对象
    IFormatter Fmt = new BinaryFormatter();
    //创建Stream类型引用fs,并传递fn作路径参数
    Stream fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.None);
    //调用Fmt的Serialize方法,传递fs和Dt参数
    Fmt.Serialize(fs, Dt);
    //关闭fs对象
    fs.Close();
    //输出成功信息
    MessageBox.Show("序列化完成");
    }
             private void DeserBtn_Click(object sender, EventArgs e)
    {
    try
    {
    //创建FileStream类型引用fs,并传递fn作路径参数,文件模式为打开文件
    FileStream fs = new FileStream(fn, FileMode.Open);
    //创建BinaryFormatter类对象Fmt
    IFormatter Fmt = new BinaryFormatter();
    //调用Fmt对象Deserialize方法,传递fs
    //将fs流中的对象转换为Details类型,并将引用赋值给Dt
    Details Dt = (Details)Fmt.Deserialize(fs);
    //将Dt属性值赋值给以下两个控件的Text属性值
    nametxtnew.Text = Dt.Name;
    nicknametxtnew.Text = Dt.NickName;
    }
    //捕捉并显示文件未找到异常
    catch (FileNotFoundException ex)
    {
    string str = String.Format("异常信息:{0}", ex.Message);
    MessageBox.Show(str);
    }
    }       
    }
    [Serializable]
    //定义Details类,实现ISerializable接口
    public class Details : ISerializable
    {
    string _name;
    string _nickname;       
    //定义两个公共属性,可以读写相应的私有字段
    public string Name
    {
    get
    {
    return _name;
    }
    set
    {
    _name = value;
    }
    }
    public string NickName
    {
    get
    {
    return _nickname;
    }
    set
    {
    _nickname = value;
    }
    }
    public Details() { }
    //重载构造函数,接收两个参数
    private Details(SerializationInfo inputinfo, StreamingContext sc)
    {
    int i;
    //获取"Person Name"名称的值赋值给_name字段
    _name = inputinfo.GetString("Person Name");
    //获取_name字段内容中'>'字符索引值加1的整数值
    i = _name.IndexOf('>') + 1;
    //截取索引i开始的字符串内容,并赋值给_name字段
    _name = _name.Substring(i);
    //获取"Person Name"名称的值赋值给_name字段
    _nickname = inputinfo.GetString("Person NickName");
    //获取_name字段内容中'>'字符索引值加1的整数值
    i = _nickname.IndexOf('>') + 1;
    //截取索引i开始的字符串内容,并赋值给_nickname字段
    _nickname = _nickname.Substring(i);
    }
    //实现ISerializable接口的GetObjectData方法,接收两个参数
    void ISerializable.GetObjectData(SerializationInfo outputinfo, StreamingContext sc)
    {
    //修改所需序列化的字段值,并修改名称,填充到outputinfo对象
    outputinfo.AddValue("Person Name", "The boy's name is -->" + _name);
    outputinfo.AddValue("Person NickName", "The boy's nickname is -->" + _nickname);
    }
    }
    }

    程序运行后,除了Text属性为"文件路径"的容器(GroupBox容器控件)中的控件外,窗体大部分控件为不可用状态。输入文件名到该容器的文本框控件中(即路径为程序集当前目录),结果如图7.54所示。

    单击"确定路径"按钮后,窗体中其他控件均为可用状态,而Text属性为"文件路径"的容器中的控件变为不可用状态。接着在Text属性为"原始对象数据"的容器中的文本框控件中,输入2个字符串值,并单击"序列化"按钮,结果如图7.55所示。

    (点击查看大图)图7.54 输入文件路径
    (点击查看大图)图7.55 完成序列化
    首先程序创建Details类的对象,并根据输入值对该对象进行了初始化操作。然后将该对象进行序列化操作,自动调用Details类中实现的 GetObjectData()方法,修改字段值,并指定了相应的键值。在程序集所在的目录下已经创建了BoyName.dat文件,在Visual Studio 2005/Visual Studio 2008中打开"BoyName.dat"文件,如图7.56所示。
    (点击查看大图)图7.56 "BoyName.dat"文件内容

    从图7.56中可看出,首先原始对象的字段数据进行成功的修改,_name字段值前面加上了"The boy's name is",_nickname字段值前面加上"The boy's nickname is"。其次,字段的名称没有被持久化到dat文件中,其对应键值分别被修改为"Person Name"和"Person NickName"。最后,单击"反序列化"按钮,结果如图7.57所示。

    (点击查看大图)图7.57 完成反序列化并输出

    创建Details类的新对象,其字段数据和原始对象一致,这说明其重载构造函数的操作成功。Details类的重载构造函数序列化时修改的部分进行了逆向操作,还原了原始对象的数据。

    解析

    一般情况下,序列化的过程细节并不需要考虑,但是在开发程序时要对序列化的过程进行微操作,可以使用自定义序列化完成。常用的自定义序列化方法在定义可序列化的类型时,使之实现using System.Runtime.Serialization..ISerializable接口,当实现该接口后,序列化该类对象的过程将自动调用该类实现的GetObjectData()方法,开发者所需的微操作可以定义在这个GetObjectData()方法中。相应地,在反序列化的过程中也可以对过程进行干预,反序列化是根据持久化的数据信息重新创建该类的对象。实现ISerializable接口的类将使用重载的构造函数创建新对象,可以将干预反序列化过程的代码编写在该类重载构造函数中,如以下代码所示:

    public class Details : ISerializable
    {
    public Details() { }
    //重载构造函数,接收两个指定类型的参数
    private Details(SerializationInfo inputinfo, StreamingContext sc)
    {
    干预反序列化过程的微操作代码;
    }
    //实现ISerializable接口的GetObjectData方法,接收2个参数
    void ISerializable.GetObjectData(SerializationInfo outputinfo, StreamingContext sc)
    {
    //修改所需序列化的字段值,并填充到outputinfo对象
    outputinfo.AddValue("键名", 对序列化字段的修改值);
    }
    }
    以上代码中,重载构造函数必须接收指定类型的参数,而实现接口的GetObjectData()方法,调用outputinfo参数的AddValue()方法,即可对序列化过程的数据进行微操作。这个AddValue()方法有多个重载版本,这里用于修改字段值。
  • 相关阅读:
    每天进步一点点之查找
    每天进步一点点之堆栈思想
    每天进步一点点之大端存储和小端存储
    每天进步一点点之线性表的考察
    每天进步一点点之出栈顺序考点
    React Native 混合开发与实现
    谈谈JavaScript异步代码优化
    谈谈前端异常捕获与上报
    vue插件编写与实战
    vue项目构建与实战
  • 原文地址:https://www.cnblogs.com/zhangq723/p/1707241.html
Copyright © 2020-2023  润新知