序列化就是将对象的状态信息转换为 可以存储或传输的Object的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从 存储区中读取或反序列化对象的状态,重新创建该对象。
序列化是将对象状态转换为可保持或 传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
序列化的目的:
1. 以某种存储形式使自定义对象持久 化;
2. 将对象从一个地方传递到另一个地 方。
.NET Framework 提供两种序列化技术:
1. 二进制序列化,保持类型保真度,这 对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。您可以将对象序列化到流、磁盘、 内存和网络等等。
2. XML序列化,仅序列化公共属性和字段,且不保持类型保真度。当您要提供或使用数据而不限制使用该数据的应用程序时,这一点是很有用 的。由于 XML 是一个开放式标准,因此,对于通过 Web 共享数据而言,这是一个很好的选择。
下面使用BinaryFormatter序列化类Book作为例子来体会什么是序列化。
定义类Book:
[Serializable]
public class Book
{
string name;
float price;
string author;
public Book(string bookname, float bookprice, string bookauthor)
{
name = bookname;
price = bookprice;
author = bookauthor;
}
}
在类的上面增加了属性Serializable。(如果不加这个属性,将抛出SerializationException异常)。通过这个属性将Book标志为可以序列化的。当然也有另一种 方式使类Book可以序列化,那就是实行ISerializable接口了。Note:Serializable属性是不能被继承的。
如果你不想序列化某个变量,该怎么 处理呢?很简单,在其前面加上属性[NonSerialized]。比如我不想序列化
string author;
那我只需要
[NonSerialized]
string author;
接下来就是见证如何序列化的时刻:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
首先创建Book实例,like this:
Book book = new Book("Day and Night", 30.0f, "Bruce");
接着当然要创建一个文件了,这个文件就是用来存放我们要序列化的信息了。
FileStream fs = new FileStream(@"C:\book.dat", FileMode.Create);
序列化的实现也很简单,like this:
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, book);
完整代码如下:
static void Main(string[] args)
{
Book book = new Book("Day and Night", 30.0f, "Bruce");
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Create))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, book);
}
book = null;
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
book = (Book)formatter.Deserialize(fs);//这里返回值是object
}
}
序列化 (serialization)
将对象的状态信息转换为可以存储或传输的窗体的过程。在序列化期间,对 象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化使其他代码可以查 看或修改那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission。在默认策略下,通过 Internet 下载的代码或 Intranet 代码不会授予该权限;只有本地计算机上的代码才被授予该权限。
通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列 化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设 置对象状态,这也与可访问性规则无关。
对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列 化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码 获得该权限。
.NET Framework 提供两种序列化技术:
* 二进制序列化保持类型保真度,这对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。 您可以将对象序列化到流、磁盘、内存和网络等等。远程处理使用序列化“通过值”在计算机或应用程序域之间传递对象。
* XML 序列化仅序列化公共属性和字段,且不保持类型保真度。当您要提供或使用数据而不限制使用该数据的应用程序时,这一点是很有用的。由于 XML 是一个开放式标准,因此,对于通过 Web 共享数据而言,这是一个很好的选择。SOAP 同样是一个开放式标准,这使它也成为一个颇具吸引力的选择。
下面是一个序列化的例子:摘自于MSDN
该程序运行在Console应用程序下:
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace Microsoft.Samples.CustomOrder
{
public class OrderedClass
{
private int field1;
private string field2;
private string field3;
[XmlElement(Order = 3)]
public string Field3
{
get { return field3; }
set { field3 = value; }
}
[XmlElement(Order = 1)]
public int Field1
{
get { return field1; }
set { field1 = value; }
}
[XmlElement(Order = 2)]
public string Field2
{
get { return field2; }
set { field2 = value; }
}
public OrderedClass()
{
field1 = 1;
field2 = "String1";
field3 = "String2";
}
}
public class UnorderedClass
{
private int field1;
private string field2;
private string field3;
public string Field3
{
get { return field3; }
set { field3 = value; }
}
public int Field1
{
get { return field1; }
set { field1 = value; }
}
public string Field2
{
get { return field2; }
set { field2 = value; }
}
public UnorderedClass()
{
field1 = 1;
field2 = "String1";
field3 = "String2";
}
}
static class Program
{
static void Main()
{
UnorderedClass unordered = new UnorderedClass();
OrderedClass ordered = new OrderedClass();
XmlSerializer unorderedSerializer =
new XmlSerializer(typeof(UnorderedClass));
XmlSerializer orderedSerializer =
new XmlSerializer(typeof(OrderedClass));
Console.WriteLine("Unordered serialization:\n");
unorderedSerializer.Serialize(Console.Out, unordered);
Console.WriteLine("\n\nOrdered serialization:\n");
orderedSerializer.Serialize(Console.Out, ordered);
Console.ReadLine();
}
}
}
简单来说序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,流的概念这里不用多说(就是I/O),我们可以对流化后的对象进行 读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)!在对对象流进行读写操作时会引发一些问题,而序列化机制正是用来 解决这些问题的!
问题的引出:
如上所述,读写对象会有什么问题呢?比如:我要将对象写入一个磁盘文件而后再将其读出来会有什么问题吗?别急,其中一个最大的问题就是对象引用!举个例子 来说:假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为 对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个 空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所 希望的!
以下序列化机制的解决方案:
1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)
2.当要保存一个对象时,先检查该对象是否被保存了。
3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象
通过以上的步骤序列化机制解决了对象引用的问题!
序列化的实现
将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。