序列化

注意

此內容是由 Pearson Education, Inc. 授權轉載自架構設計指導方針:可重複使用 .NET 程式庫的慣例、慣用語和模式,第 2 版。 該版於 2008 年出版,該書自那以後已於第三版進行了全面修訂。 此頁面的某些資訊可能已過期。

序列化是程序,將物件轉換成可輕易保存或傳輸的形式。 例如,您可序列化物件,使用 HTTP 透過網際網路傳輸,並在目的地電腦上還原序列化。

.NET Framework 提供已針對多個序列化案例最佳化的三個主要序列化技術。 下表列出這些技術以及與這些技術相關的主要 Framework 型別。

技術名稱 主要類型 案例
資料合約序列化 DataContractAttribute
DataMemberAttribute
DataContractSerializer
NetDataContractSerializer
DataContractJsonSerializer
ISerializable
一般持續性
Web 服務
JSON
XML 序列化 XmlSerializer XML 格式,可完全控制 XML 的形狀
執行階段 - 序列化 (二進位和 SOAP) SerializableAttribute
ISerializable
BinaryFormatter
SoapFormatter
.NET 遠端處理

✔️ 當您設計新的型別時,請務必考量序列化。

選擇要支援的正確序列化技術

✔️ 如果可能需要在 Web 服務中持續保存或使用類型的執行個體,請考慮支援「資料合約序列化」。

✔️ 如果您需要針對序列化類型時所產生之 XML 格式的更大控制權,請考慮支援「XML 序列化」來取代資料合約序列化,或是兩者都支援。

在您需要使用資料合約序列化所不支援的 XML 建構的某些互通性情況下 (例如,為了產生 XML 屬性),就可能需要這樣的處理方式。

✔️ 如果類別的執行個體需要橫跨 .NET 遠端處理界限,請考慮支援「執行階段序列化」。

❌ 請避免針對一般持續性理由來支援執行階段序列化或 XML 序列化。 請改用資料合約序列化。

支援資料合約序列化

類型可以將 DataContractAttribute 套用至類型,並將 DataMemberAttribute 套用至類型的成員 (欄位和屬性) 來支援資料合約序列化。

✔️ 如果可以在部分信任中使用型別,請考慮將型別的資料成員標記為 public。

在完全信任中,資料合約序列化程式可以序列化及還原序列化非 public 型別和成員,但是只有 public 成員可以在部分信任中序列化及還原序列化。

✔️ 請針對具有 DataMemberAttribute 的所有屬性實作 getter 和 setter。 資料合約序列化程式需要 getter 和 setter,才能考慮將此型別序列化。 (在 .NET Framework 3.5 SP1 中,某些集合屬性可以是僅限 get-only。)如果此型別不會在部分信任中使用,則其中一個或兩個屬性存取子可以不是 public。

✔️ 請考慮針對還原序列化之執行個體的初始化使用序列化回呼。

當還原序列化物件時,不會呼叫建構函式。 (此規則有下列幾項例外狀況。在還原序列化期間,系統會呼叫標示為 CollectionDataContractAttribute 的集合建構函式。)因此,正常建構期間所執行的任何邏輯都需要實作為其中一個序列化回呼。

OnDeserializedAttribute 是最常用的回呼屬性。 此系列中的其他屬性為 OnDeserializingAttributeOnSerializingAttributeOnSerializedAttribute。 這些屬性可用來分別標記在還原序列化之前、序列化之前以及最後在序列化之後所執行的回呼。

✔️ 當您還原序列化複雜物件圖形時,請考慮使用 KnownTypeAttribute 來指示應該使用的具象型別。

✔️ 當建立或變更可序列化的型別時,請務必考慮回溯相容性與向前相容性。

請牢記,型別之未來版本的序列化資料流可以還原序列化成該型別的目前版本,反之亦然。

請務必了解資料成員 (即使是 private 和內部成員) 在型別的未來版本中無法變更其名稱、型別或甚至是順序,除非採取特別的步驟,利用資料合約屬性的明確參數來保留合約。

在變更可序列化的型別時,請測試序列化的相容性。 請嘗試將新的版本還原序列化成舊的版本,反之亦然。

✔️ 請考慮實作 IExtensibleDataObject 來允許在型別的不同版本之間往返。

此介面可讓序列化程式確保往返期間不會有任何資料遺失。 IExtensibleDataObject.ExtensionData 屬性用於儲存目前版本未知型別未來版本的任何資料,因此無法將其儲存在資料成員中。 當目前版本接著序列化並還原序列化成未來版本時,其他資料將會在序列化資料流中提供。

支援 XML 序列化

資料合約序列化是 .NET Framework 中的主要 (預設) 序列化技術,但是資料合約序列化不支援一些序列化情節。 例如,它無法讓您完全控制序列化程式所產生或使用之 XML 的形狀。 如果需要這樣的精確控制,必須使用「XML 序列化」,而且您需要設計您的類型來支援這項序列化技術。

❌ 請避免專門為了 XML 序列化來設計型別,除非您有非常強烈的理由為了控制所產生之 XML 的形狀。 這項序列化技術已經由前一節所討論的資料合約序列化所取代。

✔️ 如果您希望對序列化 XML 的形狀有更大的控制權,而不是套用 XML 序列化屬性來使用提供的控制權,請考慮實作 IXmlSerializable 介面。 此介面的兩個方法 ReadXmlWriteXml 可讓您完全控制序列化的 XML 資料流。 您也可以藉由套用 XmlSchemaProviderAttribute 來控制為此型別產生的 XML 結構描述。

支援執行階段序列化

執行階段序列化是 .NET 遠端處理所使用的技術。 如果您認為您的型別將會使用 .NET 遠端處理來傳輸,則需要確定型別有支援執行階段序列化。

「執行階段序列化」的基本支援可以藉由套用 SerializableAttribute 來提供,而更進階的案例則牽涉到實作簡單的「執行階段可序列化模式」(實作 ISerializable 並提供序列化建構函式)。

✔️ 如果您的型別將會搭配 .NET 遠端處理使用,請考慮支援執行階段序列化。 例如,System.AddIn 命名空間會使用 .NET 遠端處理,所以在 System.AddIn 增益集之間交換的所有型別都需要支援執行階段序列化。

✔️ 如果您想要擁有序列化處理序的完整控制權,請考慮實作「執行階段可序列化模式」。 例如,如果您想要在資料序列化或還原序列化時加以轉換。

此模式非常簡單。 您只需要實作 ISerializable 介面,並提供還原序列化物件時使用的特殊建構函式。

✔️ 請讓序列化建構函式處於受保護狀態,並提供兩個參數,這兩個參數的型別與名稱與此處範例所顯示的一模一樣。

[Serializable]
public class Person : ISerializable
{
    protected Person(SerializationInfo info, StreamingContext context)
    {
        // ...
    }
}

✔️ 請務必明確實作 ISerializable 成員。

✔️ 請務必將連結需求套用至 ISerializable.GetObjectData 實作。 如此可確保只有完全受信任的核心和執行階段序列化程式可存取此成員。

Portions © 2005, 2009 Microsoft Corporation. 著作權所有,並保留一切權利。

獲 Pearson Education, Inc. 的授權再版,從 Krzysztof Cwalina 和 Brad Abrams 撰寫,並在 2008 年 10 月 22 日由 Addison-Wesley Professional 出版,作為 Microsoft Windows Development Series 一部份的 Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition 節錄。

另請參閱