在C#中,利用SerializableAttribute可以很方便的实现对象的串行化,缺点是占用空间大。本文除了介绍该属性的用法之外,还将介绍一种自定义串行化功能的实现方案。
以下代码展示了SerializableAttribute的基本用法:
- using System;
- using System.IO;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- namespace UseSerializable
- {
- [Serializable]
- class PointF
- {
- public float x;
- public float y;
- }
- [Serializable]
- class CircleF
- {
- public PointF Center = new PointF();
- public float Radius;
- }
- class Program
- {
- static void Main(string[] args)
- {
- CircleF circle = new CircleF();
- circle.Center.x = 1.2F;
- circle.Center.y = 1.8F;
- circle.Radius = 1.0F;
- FileStream fsWriter = File.OpenWrite(@"D:/Sample.dat");
- BinaryFormatter fmt = new BinaryFormatter();
- fmt.Serialize(fsWriter, circle);
- fsWriter.Close();
- FileStream fsReader = File.OpenRead(@"D:/Sample.dat");
- CircleF cif = (CircleF)fmt.Deserialize(fsReader);
- fsReader.Close();
- Console.WriteLine(string.Format("{0}, {1}", cif.Center.x, cif.Center.y));
- Console.WriteLine(cif.Radius);
- }
- }
- }
下图是串行化后的文件内容:
从中大致可以看出C#编译器是如何完成对象的串行化输入输出的。
遗憾的是,明显感觉到C#的串行化功能保存了大量的信息,这在很多应用中是难以忍受的。
试想一下,在C/C++中,程序员编制的串行化代码,保存的信息量在极限情况下只有3个float数据,共12字节。
出于以上原因,在C#中有必要设计自己的串行化方案。利用System.IO空间中的BinaryWriter和BinaryReader可以轻松实现。
- using System;
- using System.Text;
- using System.IO;
- namespace UseSerializable
- {
- interface ISerializable
- {
- void Serialize(Stream output, Encoding encoding);
- void Deserialize(Stream input, Encoding encoding);
- }
- class PointF : ISerializable
- {
- public float x;
- public float y;
- public void Serialize(Stream output, Encoding encoding)
- {
- BinaryWriter bw = new BinaryWriter(output, encoding);
- bw.Write(x);
- bw.Write(y);
- }
- public void Deserialize(Stream input, Encoding encoding)
- {
- BinaryReader br = new BinaryReader(input, encoding);
- x = br.ReadSingle();
- y = br.ReadSingle();
- }
- }
- class CircleF : ISerializable
- {
- public PointF Center = new PointF();
- public float Radius;
- public void Serialize(Stream output, Encoding encoding)
- {
- Center.Serialize(output, encoding);
- BinaryWriter bw = new BinaryWriter(output, encoding);
- bw.Write(Radius);
- }
- public void Deserialize(Stream input, Encoding encoding)
- {
- Center.Deserialize(input, encoding);
- BinaryReader br = new BinaryReader(input, encoding);
- Radius = br.ReadSingle();
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- CircleF circle = new CircleF();
- circle.Center.x = 1.2F;
- circle.Center.y = 1.8F;
- circle.Radius = 1.0F;
- FileStream fsWriter = File.OpenWrite(@"D:/Sample.dat");
- circle.Serialize(fsWriter, Encoding.Default);
- fsWriter.Close();
- FileStream fsReader = File.OpenRead(@"D:/Sample.dat");
- CircleF cif = new CircleF();
- cif.Deserialize(fsReader, Encoding.Default);
- fsReader.Close();
- Console.WriteLine("{0}, {1}", cif.Center.x, cif.Center.y);
- Console.WriteLine(cif.Radius);
- }
- }
- }
串行化后的数据只有12字节,请参考下图:
总结:
如果不考虑对象的存储空间,使用编译环境支持的Serializable属性是最快捷的方法;
如果对象数量非常大,几千个甚至几万个以上,可以考虑自定义串行化方案。
附VS2005自动生成的类图: