C#对象序列化(3)

编写CustomSerialize项目的Form1.cs如如代码7.27所示。

代码7.27  自定义序列化:Form1.cs

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()方法有多个重载版本,这里用于修改字段值。
posted @ 2009-11-22 20:33  杨子宜  阅读(190)  评论(0编辑  收藏  举报