[C#] 只是想簡單說下序列化,
只是想簡單說下序列化
【博主】反骨仔 【原文地址】http://www.cnblogs.com/liqingwen/p/5902005.html
目錄
一、序列化的含義
序列化是將對象處理為字節流以存儲對象或傳輸到內存、數據庫或文件。其主要目的是保存對象的狀態,以便可以在需要時重新創建對象。相反的過程稱為反序列化。
1.1 序列化的工作方式
此圖顯示序列化的整個過程。
圖1.1-1
對象被序列化為流。流傳遞的不僅是數據,還包括有關對象類型的信息,如對象的版本、區域性和程序集名稱。通過該流,可以將對象存儲在數據庫、文件或內存中。
1.2 用於序列化
通過序列化,開發人員可以保存對象的狀態,並在需要時重新創建該對象,從而提供對象的存儲以及數據交換。通過序列化,開發人員還可以執行類似如下的操作:通過 Web 服務將對象發送到遠程應用程序、將對象從一個域傳遞到另一個域、以 XML 字符串的形式跨防火牆傳遞對象,或者跨應用程序維護安全信息或用戶特定信息。
1.3 使對象可序列化
若要序列化對象,您需要待序列化的對象、要包含序列化對象的流,以及一個 Formatter。 System.Runtime.Serialization包含序列化和反序列化對象所需的類。
將 SerializableAttribute 特性應用於一個類型可指示該類型的實例可以序列化。嘗試序列化時,如果類型沒有 SerializableAttribute 特性,將引發SerializationException 異常。
如果不希望類中的字段可序列化,請應用 NonSerializedAttribute 特性。如果可序列化類型的字段包含指針、句柄或其他一些專用於特定環境的數據結構,並且不能在不同的環境中以有意義的方式重建,則可能需要使該字段不可序列化。
如果已序列化的類包含對標記為 SerializableAttribute 的其他類的對象的引用,則也將序列化這些對象。
1.3.1 二進制序列化和 XML 序列化
可以使用二進制序列化或 XML 序列化。在二進制序列化中,會序列化所有成員(甚至包括那些只讀成員),從而可以提高性能。XML 序列化提供了可讀性更好的代碼,並在對象共享和使用方面提供了更大的靈活性,以便實現互操作性。
1.3.2 二進制序列化
二進制序列化使用二進制編碼來生成精簡的序列化,以用於存儲或基於套接字的網絡流等。
1.3.3 XML 序列化
XML 序列化將對象的公共字段和屬性或者方法的參數及返回值序列化為符合特定 XML 架構定義語言 (XSD) 文檔的 XML 流。XML 序列化會生成具有轉換為 XML 的公共屬性和字段的強類型類。 System.Xml.Serialization 包含序列化和反序列化 XML 所需的類。
您可以將特性應用於類和類成員,以控制 XmlSerializer 序列化或反序列化類實例的方式。
1.3.4 SOAP 序列化
XML 序列化還可用於將對象序列化為符合 SOAP 規范的 XML 流。SOAP 是一種基於 XML 的協議,它是專門為使用 XML 來傳輸過程調用而設計的。如同常規的 XML 序列化,特性可用於控制 XML Web services 生成的文本樣式的 SOAP 消息。
1.3.5 基本序列化和自定義序列化
可以通過兩種方式執行序列化:基本序列化和自定義序列化。基本序列化使用 .NET Framework 來自動序列化對象。
1.3.5.1 基本序列化
基本序列化的唯一要求是對象必須應用 SerializableAttribute 特性。 NonSerializedAttribute 可用於禁止序列化特定字段。
使用基本序列化時,對象的版本控制可能會產生問題,在這種情況下,自定義序列化可能更合適。基本序列化是執行序列化的最簡單的方法,但對進程提供的控制並不多。
1.3.5.2 自定義序列化
在自定義序列化中,可以准確地指定將序列化哪些對象以及如何完成序列化。類必須標記為 SerializableAttribute,並實現 ISerializable 接口。
如果希望同樣以自定義方式反序列化對象,則必須使用自定義構造函數。
1.3.6 設計器序列化
設計器序列化是一種特殊形式的序列化,它涉及通常與開發工具關聯的對象持久性的種類。設計器序列化是將對象圖轉換為以後可用於恢復對象圖的源文件的過程。源文件可以包含代碼、標記,甚至包含 SQL 表信息。有關更多信息,請參見Designer Serialization Overview。
二、通過序列化保存對象數據
雖然您可以在設計時將對象的屬性設置為默認值,但是,如果該對象被損環,則在運行時輸入的所有值均會丟失。 可以使用序列化在實例之間保持對象數據,從而能夠存儲值並且在下次實例化對象時檢索這些值。
在本演練中,將創建一個簡單的對象,並將該對象的數據保存到文件中。然後,當您重新創建對象時將從該文件檢索數據。最後,將修改代碼以使用 SOAP 格式保持對象。
2.1 使用序列化保存對象
1 [Serializable] //將類標記為可序列化
2 public class Coupon : INotifyPropertyChanged
3 {
4 public decimal Amount { get; set; }
5
6 public float InterestRate { get; set; }
7
8 public int Term { get; set; }
9
10 private string _name;
11
12 public string Name
13 {
14 get { return _name; }
15 set
16 {
17 _name = value;
18 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Customer"));
19 }
20 }
21
22 [field: NonSerialized()] //將可序列化的類中的某字段標記為不被序列化
23 public event PropertyChangedEventHandler PropertyChanged;
24
25 public Coupon(decimal amount, float interestRate, int term, string name)
26 {
27 Amount = amount;
28 InterestRate = interestRate;
29 Term = term;
30 _name = name;
31 }
32 }
Coupon.cs
1 static void Main(string[] args)
2 {
3 const string fileName = @"demo1.txt";
4 var coupon = new Coupon(10000, 0.2f, 1, "反骨仔");
5
6 using (var stream = File.Create(fileName))
7 {
8 var deserializer = new BinaryFormatter(); //二進制格式序列化器
9 deserializer.Serialize(stream, coupon); //序列化對象到文件中
10 }
11 }
圖2-1
現在嘗試反序列化,看看與之前 Coupon 對象的值是否一致。
1 static void Main(string[] args)
2 {
3 const string fileName = @"demo1.txt";
4 //var coupon = new Coupon(10000, 0.2f, 1, "反骨仔");
5
6 //判斷該文件是否存在
7 if (!File.Exists(fileName))
8 {
9 return;
10 }
11
12 using (var stream = File.OpenRead(fileName))
13 {
14 var deserializer = new BinaryFormatter(); //二進制序列化器
15 var coupon = deserializer.Deserialize(stream) as Coupon; //反序列化
16
17 if (coupon == null)
18 {
19 return;
20 }
21
22 Console.WriteLine($"{nameof(Coupon)}:");
23 Console.WriteLine($" {nameof(coupon.Amount)}: {coupon.Amount}");
24 Console.WriteLine($" {nameof(coupon.InterestRate)}: {coupon.InterestRate}%");
25 Console.WriteLine($" {nameof(coupon.Term)}: {coupon.Term}");
26 Console.WriteLine($" {nameof(coupon.Name)}: {coupon.Name}");
27 }
28
29 Console.Read();
30 }
圖2-2
2.2 使用 SOAP 格式保存對象
1 static void Main(string[] args)
2 {
3 const string fileName = @"demo1.txt";
4 var coupon = new Coupon(10000, 0.2f, 1, "反骨仔");
5
6 using (var stream = File.Create(fileName))
7 {
8 var deserializer = new SoapFormatter(); //Soap 格式化器
9 deserializer.Serialize(stream, coupon); //序列化
10 }
11 }
圖2-3
反序列化時也采用 SoapFormatter 即可,結果同圖2-2。
var deserializer = new SoapFormatter(); //Soap 格式化器
var coupon = deserializer.Deserialize(stream) as Coupon; //反序列化
【注意】本示例將數據存儲到二進制或 SOAP 格式的文件中。不應將這些格式用於敏感數據,如密碼或信用卡信息。
【備注】二進制格式對於大多數 Windows 應用程序均適用。但對於 Web 應用程序或 Web 服務,您可能希望使用 SOAP 格式將對象保存到 XML 文件中,以使對象易於共享。
同樣,也可以通過 XmlSerializer 將對象序列化保存在 XML 文件。我們可以根據需求選擇合適的序列化器,操作基本是一樣的。
眾說紛纭
@hi丶小時候 使用 SerializableAttribute 特性時,是不建議使用自動屬性的,序列化後的字段都是多出 k_BackingField<> 17個字符,如果對象很大會浪費一部分流量,建議使用 DataContractAttribute 和 DataMemberAttribute
@梁逸晨 除非對方系統強制要求 SOAP 才能通信,否則該人人抵制這麼反人類的東西,建議樓主 JSON 或 Protobuf
【參考】微軟官方文檔