序列化和反序列化相信大家都经常听到,也都会用, 然而有些人可能不知道:.net为什么要有这个东西以及.net Frameword如何为我们实现这样的机制, 在这里我也是简单谈谈我对序列化和反序列化的一些理解。
一、什么序列化和反序列化
序列化通俗地讲就是将一个对象转换成一个字节流的过程,这样就可以轻松保存在磁盘文件或数据库中。反序列化是序列化的逆过程,就是将一个字节流转换回原来的对象的过程。
然而为什么需要序列化和反序列化这样的机制呢?这个问题也就涉及到序列化和反序列化的用途了,
对于序列化的主要用途有:
1)、将应用程序的状态保存在一个磁盘文件或数据库中,并在应用程序下次运行时恢复状态。例如, Asp.net 中利用序列化和反2)、序列化来保存和恢复会话状态。
3)、一组对象可以轻松复制到Windows 窗体的剪贴板中,再粘贴回同一个或者另一个应用程序。
将对象按值从一个应用程序域中发送到另一个程序域
并且如果把对象序列化成内存中的字节流,就可以利用一些其他的技术来处理数据,例如,对数据进行加密和压缩等。
二、序列化和反序列简单使用
.Net Framework 提供二种序列化方式:
1)、二进制序列化
2)、XML 和SOAP序列化
序列化和反序列化的简单使用:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Serializable
{
[Serializable]
public class Person
{
public string personName;
[NonSerialized]
public string personHeight;
private int personAge;
public int PersonAge
{
get { return personAge; }
set { personAge = value; }
}
public void Write()
{
Console.WriteLine("Person Name: "+personName);
Console.WriteLine("Person Height: " +personHeight);
Console.WriteLine("Person Age: "+ personAge);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.personName = "Jerry";
person.personHeight = "175CM";
person.PersonAge = 22;
Stream stream = Serialize(person);
//为了演示,都重置
stream.Position = 0;
person = null;
person = Deserialize(stream);
person.Write();
Console.Read();
}
private static MemoryStream Serialize(Person person)
{
MemoryStream stream = new MemoryStream();
// 构造二进制序列化格式器
BinaryFormatter binaryFormatter = new BinaryFormatter();
// 告诉序列化器将对象序列化到一个流中
binaryFormatter.Serialize(stream, person);
return stream;
}
private static Person Deserialize(Stream stream)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
return (Person)binaryFormatter.Deserialize(stream);
}
}
}
</div>
主要是调用System.Runtime.Serialization.Formatters.Binary命名空间下的BinnaryFormatter类来进行序列化和反序列化,调用反序列化后的结果截图:

从中可以看出除了标记NonSerialized的其他成员都能序列化,注意这个属性只能应用于一个类型中的字段,而且会被派生类型继承。
SOAP 和XML 的序列化和反序列化和上面类似,只需要改下格式化器就可以了, 这里我就不列出来了。
三、控制序列化和反序列化
有两种方式来实现控制序列化和反序列化:
通过OnSerializing, OnSerialized,OnDeserializing, OnDeserialized,NonSerialized和OptionalField等属性
实现System.Runtime.Serialization.ISerializable接口
第一种方式实现控制序列化和反序列化代码:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ControlSerialization
{
[Serializable]
public class Circle
{
private double radius; //半径
[NonSerialized]
public double area; //面积
public Circle(double inputradiu)
{
radius = inputradiu;
area = Math.PI * radius * radius;
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
area = Math.PI * radius * radius;
}
public void Write()
{
Console.WriteLine("Radius is: " + radius);
Console.WriteLine("Area is: " + area);
}
}
class Program
{
static void Main(string[] args)
{
Circle c = new Circle(10);
MemoryStream stream =new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
// 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。
formatter.Serialize(stream,c);
stream.Position = 0;
c = null;
c = (Circle)formatter.Deserialize(stream);
c.Write();
Console.Read();
}
}
}
</div>
运行结果为:

注意:如果注释掉 OnDeserialized属性的话,area字段的值就是0了,因为area字段没有被序列化到流中。
在上面需要序列化的对象中,格式化器只会序列化对象的radius字段的值。area字段中的值不会序列化,因为该字段已经应用了NonSerializedAttribute属性,然后我们用Circle c=new Circle(10)这样代码构建一个Circle对象时,在内部,area会设置一个约为314.159这样的值,这个对象序列化时,只有radius的字段的值(10)写入流中, 但当反序列化成一个Circle对象时,它的area字段的值会初始化为0,而不是约314.159的一个值。为了解决这样的问题,所以自定义一个方法应用OnDeserializedAttribute属性。此时的执行过程为:每次反序列化类型的一个实例,格式化器都会检查类型中是否定义了 一个应用了该attribute的方法,如果是,就调用该方法,调用该方法时,所有可序列化的字段都会被正确设置。除了OnDeserializedAttribute这个定制attribute,system.Runtime.Serialization命名空间还定义了OnSerializingAttribute,OnSerializedAttribute和OnDeserializingAttribute这些定制属性。
实现ISerializable接口方式控制序列化和反序列化代码:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
namespace ControlSerilization2
{
[Serializable]
public class MyObject : ISerializable
{
public int n1;
public intn2;
[NonSerialized]
public String str;
public MyObject()
{
}
protected MyObject(SerializationInfo info, StreamingContext context)
{
n1 = info.GetInt32("i");
n2 = info.GetInt32("j");
str = info.GetString("k");
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("i", n1);
info.AddValue("j", n2);
info.AddValue("k", str);
}
public void Write()
{
Console.WriteLine("n1 is: " + n1);
Console.WriteLine("n2 is: " + n2);
Console.WriteLine("str is: " + str);
}
}
class Program
{
static void Main(string[] args)
{
MyObject obj = new MyObject();
obj.n1 = 2;
obj.n2 = 3;
obj.str = "Jeffy";
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
// 将对象序列化到内存流中,这里可以使用System.IO.Stream抽象类中派生的任何类型的一个对象, 这里我使用了 MemoryStream类型。
formatter.Serialize(stream, obj);
stream.Position = 0;
obj = null;
obj = (MyObject)formatter.Deserialize(stream);
obj.Write();
Console.Read();
}
}
}
</div>
结果为:

