序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。两个过程结合可以存储和传输数据。
.NET Framework 提供两种序列化技术:
1) 二进制序列化
这种序列化可以保持类型不变,即可以在应用程序的不同调用之间保留对象的状态。
2)XML 和SOAP 序列化
这种序列化仅序列化公共属性和字段,不保存类型。
另外还有Json序列化,需要引用Newtonsoft.Json
1 二进制序列化与反序列化
序列化可被定义为将对象的状态存储到存储媒介中的过程。在此过程中,对象的公共字段和私有字段以及类的名称(包括该类的程序集)都被转换为字节流,然后写入数据流。在以后反序列化该对象时,创建原始对象的精确副本。
序列化有两个最重要的功能:一个时将对象的状态保持在存储媒体中,以便可以在以后重新创建精确的副本;另一个是通过值将对象从一个应用程序域发送到另有一个应用程序域中。例如,序列化可用于在ASP.NET中保存会话状态并将对象复制到Windows窗体的剪贴板中。远程处理还可以试用序列化通过将对象从一个程序域传递到另一个应用程序域中。
1.1 序列化
序列化一个类最简单的方式是试用如下所示的Serializable属性标记。
[Serializable] public class AuthUserEntry { private string accountName; private int accountId; public string AccountName { } public int AccountId { } } }
下面用代码演示该类的实例是如何被序列化到一个二进制文件(.bin)中的。
AuthUserEntry user = new AuthUserEntry(); user.AccountId = 9912053; user.AccountName = "XinXin"; IFormatter formater = new BinaryFormatter(); Stream stream = new FileStream("UserInfo.bin", FileMode.Create, FileAccess.Write, FileShare.None); formater.Serialize(stream, user); stream.Close();
在这段代码中,创建流的实例和试用的格式接口后,对该格式接口调用Serialize方法,类中的所有成员变量都将被序列化,即使是哪些已被标记为私有的变量。
1.2 反序列化
要将对象还原回其以前的状态,首先,创建用于读取的流和格式化接口,然后用格式化接口反序列化该对象。下面的代码示例说明如何执行上述的操作
IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream("UserInfo.bin", FileMode.Open, FileAccess.Read, FileShare.Read); AuthUserEntry me = (AuthUserEntry) formatter.Deserialize(stream); stream.Close();
需要特别注意的是,在反序列化一个对象时不调用构造函数。
【例】二进制序列化和反序列化的方法
using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace BinarySerializableExample { [Serializable] public class AuthUserEntry { private string accountName; private int accountId; public string AccountName { get { return accountName; } set { accountName = value; } } public int AccountId { get { return accountId; } set { accountId = value; } } } class Account { static void Main(string[] args) { AuthUserEntry user = new AuthUserEntry(); user.AccountId = 9912053; user.AccountName = "XinXin"; IFormatter formater = new BinaryFormatter(); Stream stream = new FileStream("UserInfo.bin", FileMode.Create, FileAccess.Write, FileShare.None); formater.Serialize(stream, user); stream.Close(); stream = new FileStream("UserInfo.bin", FileMode.Open, FileAccess.Read, FileShare.Read); AuthUserEntry me = (AuthUserEntry)formater.Deserialize(stream); stream.Close(); Console.WriteLine("帐户号:{0}", me.AccountId); Console.WriteLine("帐户名:{0}", me.AccountName); //按回车键结束 Console.ReadLine(); } } }
输出结果为:
账号名:9912053
账户名:XinXin
打开应用程序的bin文件夹,会看到有一个生成文件UserInfo.bin,打开它会看到正是AuthUserEnty对象实例的值。
1.3 有选择的序列化
也可能在类中包含不应被序列化的字段。例如,假设一个类将线程ID 存储在成员变量中。当反序列化该类时,在序列化该类时为其存储ID 的线程可能不再运行,因此序列化该值没有意义。通过用NonSerialized 属性标记成员变量,可以防止它们被序列化,如下所示:
[Serializable] public class MyObject { public int n1; [NonSerialized] public int n2; public String str; }
2 XML和SOAP序列化与反序列化
也可以对XML 和SOAP 流对象进行序列化和反序列化,这种操作一般用于将对象转换为网络中容易传输的格式。例如,可以序列化一个对象,然后使用HTTP 通过Internet 在客户端和服务器之间传输该对象。在另一端,通过反序列化重新构造对象。
XML 序列化仅将对象的公共字段和属性值序列化为XML 流,而不转换方法、索引器、私有字段或只读属性(只读集合除外)。若要序列化对象的所有字段和属性(公共的和私有的),可以使用BinaryFormatter 序列化。XML 序列化不包括类型信息,即不能保证序列化后的对象在被反序列化时,变为同一类型的对象。
XML序列化中最主要的类是XmlSerializer 类,它的最重要的方法是Serialize 和Deserialize方法。XmlSerializer 生成的XML 流符合万维网联合会(www.w3.org)XML 架构定义语言(XSD)的建议。
使用 XmLSerializer 类,可将下列项序列化。
◆ 公共类的公共读/写属性和字段。
◆ 实现 ICollection 或 IEnumerable 的类(注意只有集合会被序列化,而公共属性却不会)。
◆ XmlElement 对象。
◆ XmlNode 对象。
◆ DataSet 对象。
2.1 序列化对象
首先,创建要序列化的对象并设置它的公共属性和字段,而且必须确定用以存储XML 流的传输格式(或者作为流,或者作为文件)。例如,如果XML 流必须以永久形式保存,则创建FileStream 对象。当反序列化对象时,传输格式将确定创建流还是文件对象。确定了传输格式之后,就可以根据需要调用Serialize 或Deserialize 方法。
其次,使用该对象的类型构造XmlSerializer。
最后,调用Serialize 方法以生成对象的公共属性和字段的XML 流表示形式或文件表示形式。
下面的示例创建一个文件:
// 第一步,创建要序列化的对象 AuthUserEntry user = new AuthUserEntry(); user.AccountId = 9912053; user.AccountName = "XinXin"; // 第二步,构造XmlSerializer 对象 XmlSerializer mySerializer = new XmlSerializer(typeof(AuthUserEntry)); // 创建StreamWriter 对象完成对文件的写操作 StreamWriter myWriter = new StreamWriter("UserInfo.xml"); // 第三步,调用Serialize 方法实现序列化 mySerializer.Serialize(myWriter, user); myWriter.Close();
2.2 反序列化对象
首先,使用要反序列化的对象的类型构造XmlSerializer。
其次,调用Deserialize 方法以产生该对象的副本。在反序列化时,必须将返回的对象强制转换为原始对象的类型。
将对象反序列化为文件的语句为:
AuthUserEntry me; // 用对象类型构造XmlSerializer 的实例 XmlSerializer mySerializer = new XmlSerializer(typeof(AuthUserEntry)); // 创建FileStream 读取文件 FileStream myFileStream = new FileStream("UserInfo.xml", FileMode.Open); // 调用Deserialize 方法并强制转换返回对象的类型 me = (AuthUserEntry) mySerializer.Deserialize(myFileStream); myFileStream.Close();
【例】Xml序列化和反序列化的方法
using System; using System.IO; using System.Xml.Serialization; namespace XMLSerializableExample { [Serializable] public class AuthUserEntry { private string accountName; private int accountId; public string AccountName { get { return accountName; } set { accountName = value; } } public int AccountId { get { return accountId; } set { accountId = value; } } } class Account { static void Main(string[] args) { // 第一步,创建要序列化的对象 AuthUserEntry user = new AuthUserEntry(); user.AccountId = 9912053; user.AccountName = "XinXin"; // 第二步,构造XmlSerializer 对象 XmlSerializer mySerializer = new XmlSerializer(typeof(AuthUserEntry)); // 创建StreamWriter 对象完成对文件的写操作 StreamWriter myWriter = new StreamWriter("UserInfo.xml"); // 第三步,调用Serialize 方法实现序列化 mySerializer.Serialize(myWriter, user); myWriter.Close(); AuthUserEntry me; // 用对象类型构造XmlSerializer 的实例 //XmlSerializer mySerializer = new XmlSerializer(typeof(AuthUserEntry)); // 创建FileStream 读取文件 FileStream myFileStream = new FileStream("UserInfo.xml", FileMode.Open); // 调用Deserialize 方法并强制转换返回对象的类型 me = (AuthUserEntry)mySerializer.Deserialize(myFileStream); myFileStream.Close(); Console.WriteLine("帐户号:{0}", me.AccountId); Console.WriteLine("帐户名:{0}", me.AccountName); //按回车键结束 Console.ReadLine(); } } }
输出结果为:
帐户号:9912053
帐户名:XinXin
打开应用程序的bin 文件夹,会看到有一个生成文件UserInfo.xml,打开它会看到正是AuthUserEntry 对象实例的值。