要让一个对象支持.Net序列化服务,用户必须为每一个关联的类加上[Serializable]特性。如果类中有些成员不适合参与序列化(比如:密码字段),可以在这些域前加上[NonSerialized]特性。
C#支持三种序列化格式:二进制格式(使用BinaryFormatter序列化器)、SOAP格式(使用SoapFormatter序列化器)、XML格式(使用XmlSerializer序列化器)。这三种序列化器的区别如下:
二进制格式可序列化一个类型的所有可序列化字段,不管它是公共字段还是私有字段。SOAP格式和XML格式仅能序列化公共字段或拥有公共属性的私有字段,未通过属性公开的私有字段将被忽略。
使用二进制格式序列化时,它不仅是将对象的字段数据进行持久化,也持久化每个类型的完全限定名称和定义程序集的完整名称(包括包称、版本、公钥标记、区域性),这些数据使得在进行二进制格式反序列化时亦会进行类型检查。SOAP格式序列化通过使用XML命名空间来持久化原始程序集信息。而XML格式序列化不会保存完整的类型名称或程序集信息。这便利XML数据表现形式更有终端开放性。如果希望尽可能延伸持久化对象图的使用范围时,SOAP格式和XML格式是理想选择。
BinaryFormatter和SoapFormatter类型通过实现IFormatter和IRemotingFormatter接口实现序列化。
IFormatter接口定义了核心的Serialize和Deserialize方法用于序列化和反序列化。
IRemotingFormatter接口重载了Serialize和Deserialize方法,使风格更适合分布式持久化。
示例代码:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Soap; using System.IO; using System.Xml.Serialization; namespace CollectionSerialize { class Program { static void Main(string[] args) { //文件名称 string fileName = "Programmers.dat"; //创建Programmer列表,并添加对象 List<Programmer> list = new List<Programmer>(); list.Add(new Programmer("Coder1", false, "C")); list.Add(new Programmer("Coder2", false, "C++")); list.Add(new Programmer("Coder3", false, "Java")); //创建文件流 Stream fStream = null; fStream = FileReset(fStream, fileName); //使用二进制序列化器 BinaryFormatter binFormat = new BinaryFormatter(); //将list序列化到文件中 binFormat.Serialize(fStream, list); //清空列表 list.Clear(); //重置流位置 fStream.Position = 0; //反序列化,注意要将结果转型 list = (List<Programmer>)binFormat.Deserialize(fStream); //输出 Print(list); fStream = FileReset(fStream, fileName); //使用XML序列化 //注意使用此构造器时必须在第一个参数传入序列化的类型,第二个参数传入序列化所涉及的相关类型 XmlSerializer xmlFormat = new XmlSerializer(typeof(List<Programmer>), new Type[] { typeof(Programmer), typeof(Person) }); //反序列化 xmlFormat.Serialize(fStream, list); list.Clear(); fStream.Position = 0; //反序列化,注意要将结果转型 list = (List<Programmer>)xmlFormat.Deserialize(fStream); Print(list); fStream = FileReset(fStream, fileName); //使用SOAP序列化 SoapFormatter soapFormat = new SoapFormatter(); //序列化,Soap不能序列化泛型对象,所以只能指定序列化一个Programmer对象 soapFormat.Serialize(fStream, list[0]); list.Clear(); fStream.Position = 0; //反序列化 list.Add((Programmer)soapFormat.Deserialize(fStream)); Print(list); fStream.Close(); Console.ReadKey(); } //输出程序员列表 static void Print(List<Programmer> list) { Console.WriteLine("程序员信息列表:"); foreach (Programmer p in list) { Console.WriteLine("姓名:{0} 性别:{1} 编程语言:{2}", p.Name, p.Sex.ToString(), p.Language); } } //重置文件 static FileStream FileReset(Stream fStream, string fileName) { //关闭文件流 if (fStream != null) { fStream.Close(); } //删除文件 File.Delete(fileName); //新建文件流 return new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); } } [Serializable] //必须添加序列化特性 public class Person { //姓名 public string Name; //性别 public bool Sex; //必须提供无参构造器,否则XmlSerializer将出错 public Person() { } //构造函数 public Person(string name, bool sex) { this.Name = name; this.Sex = sex; } } [Serializable] //必须添加序列化特性 public class Programmer : Person { //编程语言 public string Language; //必须提供无参构造器,否则XmlSerializer将出错 public Programmer() { } //构造函数 public Programmer(string name, bool sex, string language) : base(name, sex) { this.Language = language; } } }
程序运行结果如下:
需要注意的是:
1. SoapFormatter不能序列化泛型对象。
2. XmlSerializer的构造器需要传入序列化涉及的相关类型信息。