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

Effective C# 原則 25:讓你的型別支援序列化(三)

     編輯:關於C語言

序列化流與鍵值對應

序列化流以鍵/值對應保存每個元素。預設特性產生程式碼以變數名為鍵儲存值。添加 ISerializable 介面後,必須匹配鍵名與變數順序(順序即類別中定義順序。順便說,重新排列類別變數名或重新命名,都會破壞對已建立檔案的相容性。)

安全性要求

同樣要求 SerializationFormatter 安全許可權。未實作恰當保護,GetObjectData() 可能存在安全漏洞。惡意程式碼可能產生 StreamingContext,用 GetObjectData() 從物件取得值、不斷修改版本取得另一 SerializationInfo、重新組織修改物件。允許惡意開發者存取物件內部狀態、在流中修改、發送修改版本給你。要求 SerializationFormatter 許可權可封閉漏洞,確保只有受信任程式碼恰當存取類別內部狀態(原則 47)。

ISerializable 在基類的缺點

我早讓 MyType 成為密封 (sealed),強制只能為葉子類別。基類實作 ISerializable 隱式讓所有衍生類別也序列化。實作意味著所有衍生類別必須建立受保護建構函式與反序列化。為支援非密封類,必須在 GetObjectData() 建立 Hook,讓衍生類別添加自身資料到流。編譯器不捕捉此類錯誤,從流讀取衍生類時,因缺建構函式在執行期拋出例外。缺 Hook 的 GetObjectData() 也意味衍生類資料不會儲存到檔案,也無錯誤拋出。建議:在葉類別實作 Serializable。

支援衍生類別序列化的基類修改

為衍生類別序列化,基類必須支援序列化。修改 MyType 為可序列化基類:將序列化建構函式改為 protected,建立虛擬方法讓衍生類別重載並儲存資料:

[Serializable]
public class MyType : ISerializable
{
    private string _label;
    [NonSerialized] private int _value;
    private OtherClass _object;
    private const int DEFAULT_VALUE = 5;
    private int _value2;
    protected MyType(SerializationInfo info, StreamingContext cntxt)
    {
        _label = info.GetString("_label");
        _object = (OtherClass)info.GetValue("_object", typeof(OtherClass));
        try { _value2 = info.GetInt32("_value2"); }
        catch (SerializationException) { _value2 = DEFAULT_VALUE; }
    }
    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    void ISerializable.GetObjectData(SerializationInfo inf, StreamingContext cxt)
    {
        inf.AddValue("_label", _label);
        inf.AddValue("_object", _object);
        inf.AddValue("_value2", _value2);
        WriteObjectData(inf, cxt);
    }
    protected virtual void WriteObjectData(SerializationInfo inf, StreamingContext cxt) { }
}

衍生類別應提供自身序列化建構函式,重載 WriteObjectData:

public class DerivedType : MyType
{
    private int _DerivedVal;
    private DerivedType(SerializationInfo info, StreamingContext cntxt) : base(info, cntxt)
    { _DerivedVal = info.GetInt32("_DerivedVal"); }
    protected override void WriteObjectData(SerializationInfo inf, StreamingContext cxt)
    { inf.AddValue("_DerivedVal", _DerivedVal); }
}

從流讀寫值順序必須一致。先讀寫基類資料較簡單。若程式碼未對整個繼承關係精確順序序列化,序列化程式碼無效。

.NET 框架標準序列化

.NET 框架提供簡單、標準演算法支援物件序列化。若型別需持久,應遵守標準實作。若型別不支援序列化,使用此類的類別也無法序列化。為方便使用者,盡可能用預設序列化特性,預設特性不滿足時實作 ISerializable。

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