对象序列化是将对象(比如Person对象)转换为二进制数据(字节流),反序列化是将二进制数据还原为对象。对象是稍纵即逝的,不仅程序重启、操作系统重启会造成对象的消失,就是退出函数范围等都可能造成对象的消失,序列化/反序列化就是为了保持对象的持久化。就像用DV录像(序列化)和用播放器播放(反序列化)一样。对象序列化,只能针对对象的字段进行序列化。以下为序列化与反序列化两个示例。
示例1:序列化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;//需要引用的命名空间
namespace _05对象序列化
{
class Program
{
//总结:
//对象→byte[]序列化一个对象,但对象中可以包含多种内容,一个集合也可以
//作用:1.直接存储对象;2.在网络中可以直接发送对象信息
//序列化步骤:1.序列化对象:BinaryFormatter bf = new BinaryFormatter();
//2.创建文件流: using (FileStream fs=new FileStream("", FileMode.Create))
//{
//调用Serialize方法进行序列化
//bf.Serialize(fs, sly);
//}
//3.只序列化字段信息,方法不被序列化
//反序列化步骤:1.创建二进制序列化器(格式化器):BinaryFormatter bf = new BinaryFormatter();
//2.创建文件流: using (FileStream fs=new FileStream("", FileMode.Create))
//{
//调用Deserialize方法进行反序列化
//bf.Deserialize(fs);
//}
//序列化注意问题:
//1.要被序列化的对象的类型必须标记为可序列化为[Sreializable]
//2.父类也要标记
//3.类中字段或属性的类型也必须为可序列化的
static void Main(string[] args)
{
Person sly = new Person();
sly.Name = "麦兜兜";
sly.Age = 16;
sly.Email = "sly@126.com";
sly.MyCar = new Car("QQ");
//现在要想存储sly这个对象,只能是,将【"麦兜兜",16,"sly@126.com"】,只能将这些数据存储起来,
//下次用这些数据的时候,必须重新创建一个对象,然后这个对象的属性中的值,是来源于上个对象的。。
//思考:能不能直接把sly这个对象存储起来。这样的话,下次使用的时候直接拿来就是一个对象,不需要重新创建。
//对象序列化的步骤
//1.创建二进制对象序列化器
BinaryFormatter bf = new BinaryFormatter();
//创建一个文件流
using (FileStream fs = new FileStream("", FileMode.Create))
{
//2.开始执行序列化
//将对象sly,序列化到fs文件流中,最终sly就保存到了根目录(Debug)person.bin文件中。
bf.Serialize(fs, sly);
}
Console.WriteLine("ok");
Console.ReadKey();
}
}
//Person类型要想被序列化,
//1.必须Person类型本身是可序列化的(即Person类型标记为可序列化)
//2.类中所有的字段属性的类型也必须标记为可序列化的
//3.当前类型的所有父类也必须标记为可序列化的
[Serializable]
public class Person : ShenWu
{
//4.建议,在使用序列化的时候尽量避免使用自动属性,因为自动属性,每次编译的时候自动生成的字段名可能不一样,所以在反序列化的时候可能会造成问题。
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
private int _age;
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
private string _email;
public string Email
{
get
{
return _email;
}
set
{
_email = value;
}
}
private Car _myCar;
public Car MyCar
{
get { return _myCar; }
set { _myCar = value; }
}
}
[Serializable]
public class ShenWu//Person继承该类,所以也需要进行可序列化标记[Serializable]
{
public void Say()
{
Console.WriteLine("新陈代谢!");
}
}
[Serializable]
public class Car//Car作为Person中的属性字段,也需要进行可序列化标记[Serializable]
{
public Car(string brand)
{
this.Brand = brand;
}
private string _brand;
public string Brand
{
get
{
return _brand;
}
set
{
_brand = value;
}
}
}
}
说明:非网络流中需要添加序列化集引用,在本例中即添加“05对象序列化”
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using _05对象序列化;
namespace _06反序列化
{
class Program
{
static void Main(string[] args)
{
//反序列化步骤:
//1.创建二进制序列化器(格式化器)
BinaryFormatter bf = new BinaryFormatter();
using (FileStream fs = new FileStream("person.bin", FileMode.Open))
{
//2.开始执行反序列化
//在执行反序列化的时候,由于person.bin中是存储的是原来Person类型序列化后的结果,
//所以要对person.bin反序列化时,需要Person类所在的程序集。
//问题:为什么反序列化的时候需要原来定义Person类的那个程序集?
//反序列话的时候,要返回一个对象,这个对象必须根据原来Person所在的程序集才能创建,
//也就是说person.bin中包含的仅仅是一些数据,根据这些数据是无法在内存中创建对象的。
//只能是根据原来Person类型的程序集来创建对象,然后把person.bin中的数据一一对应进行赋值。
//object obj = bf.Deserialize(fs);
//对象序列化,只是对对象的一些状态信息进行序列化(比如:字段)。
//对于方法之类的根本不进行序列化,也就是说person.bin中只包含字段名和字段值,根本没有方法信息。
//但是反序列化的时候,返回的是一个对象,那么只根据这些字段信息是无法创建对象的,所以这个时候
//需要先根据原来的程序集,获取Person类型,然后在内存中创建一个Person对象,然后再把反序列化得到的字段信息赋值给这个Person对象。
Person per = (Person)bf.Deserialize(fs);//此处“Person”即“05对象序列化”中定义的Person类
Console.WriteLine("Name:{0},Age:{1},Car:{2}", per.Name, per.Age, per.MyCar.Brand);
}
Console.WriteLine("ok");
Console.ReadKey();
}
}
}