首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

Effective C# 原則 25:讓型別支援序列化,確保物件持久化與圖形完整性

     編輯:關於C#

序列化:型別的核心義務

物件持久化是基本功能。若型別不支援序列化,所有包含該型別為成員或基類的類別都將無法正確序列化,強迫消費者繞道手寫序列化邏輯,甚至因無法存取私有成員而不可能完成。

最簡單方式:Serializable 屬性

[Serializable]
public class MyType {
    private string _label;
    private int _value;
    private OtherClass _object; // OtherClass 也必須可序列化
}

所有成員皆為可序列化型別時,僅需標記屬性即可。支援二進位與 SOAP 兩種格式,自動處理物件圖(含循環參考)。

排除敏感/暫存欄位:NonSerialized 屬性

[Serializable]
public class MyType {
    private string _label;
    [NonSerialized] private int _cachedValue; // 不序列化
    private OtherClass _object;
}

反序列化時,NonSerialized 欄位保持預設值(0/null)。若需自訂初始化,實作 IDeserializationCallback.OnDeserialization(物件圖完成後呼叫),但需注意呼叫順序不固定,公開成員必須能處理欄位未初始化狀態。

版本演進與 ISerializable 自訂序列化

新增欄位會導致舊版資料反序列化失敗。實作 ISerializable 掌控完整流程:

[Serializable]
public sealed class MyType : ISerializable {
    private string _label;
    [NonSerialized] private int _value;
    private OtherClass _object;
    private int _value2; // v2 新增
    private const int DEFAULT_VALUE = 5;

    // 序列化建構函式(反序列化專用)
    private MyType(SerializationInfo info, StreamingContext ctx) {
        _label = info.GetString("_label");
        _object = (OtherClass)info.GetValue("_object", typeof(OtherClass));
        try { _value2 = info.GetInt32("_value2"); }
        catch (SerializationException) { _value2 = DEFAULT_VALUE; } // 相容 v1
    }

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx) {
        info.AddValue("_label", _label);
        info.AddValue("_object", _object);
        info.AddValue("_value2", _value2);
    }
}

關鍵點:

  • 鍵名/順序必須與預設序列化一致(依宣告順序)。
  • 要求 SerializationFormatter 安全權限,防惡意代碼竄改資料流。
  • 建議 sealed 類別實作,避免衍生類別序列化複雜度。

非密封類別的序列化擴充模式

基類建構函式改為 protected,提供 virtual WriteObjectData 讓衍生類別擴充:

protected MyType(SerializationInfo info, StreamingContext ctx) { ... }
void ISerializable.GetObjectData(...) { ...; WriteObjectData(info, ctx); }
protected virtual void WriteObjectData(SerializationInfo info, StreamingContext ctx) { }

衍生類別覆寫 WriteObjectData 並提供自身序列化建構函式呼叫 base(info, ctx)。

總結

預設用 [Serializable]、需要控制用 [NonSerialized]、版本演進/複雜圖形用 ISerializable。讓所有型別支援序列化,是對消費者負責的基本態度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved