程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Effective C#原則25 讓你的類型支持序列化(2)

Effective C#原則25 讓你的類型支持序列化(2)

編輯:關於C語言

你,做為類的設計者,非序列化成員給你多添加了一點點工作。 在序列化過程中,序列化API不會為你初始化非序列化成員。因為類型的構造函 數沒有被調用,所以成員的初始化也不會被執行。當你使用序列化特性時,非序 列成員就保存著系統默認值:0或者null。當默認的0對初始化來說是不正確的, 那麼你須要實現IDeserializationCallback 接口,來初始化這些非序列化成員 。框架會在整個對象圖反序列化以後,調用這個方法。這時,你就可以用它為所 有的非序列化成員進行初始化了。因為整個對象圖已經載入,所以你的類型上的 所有方法的調用及成員的使用都是安全的。不幸的是,這不是傻瓜式的。在整個 對象圖載入後,框架會在對象圖中每個實現了IDeserializationCallback接口的 對象上調用OnDeserialization方法。對象圖中的其它任何對象可以在 OnDeserialization正在進行時調用對象的公共成員。如果它們搶在了前面,那 麼你的非序列化成員就是null或者0。順序是無法保證的,所以你必須確保你的 所有公共成員,都能處理非序列化成員還沒有初始化的這種情況。

到目 前為止,你已經知道為什麼要為所有類型添加序列化了:非序列化類型會在要序 列化的對象中使用時帶來更多的麻煩事。你也學會了用特性來實現最簡單的序列 化方法,還包括如何初始化非序列化成員。

序列化了對象有方法在程序 的不同版本間生存。(譯注:這是一個很重要的問題,因為.Net裡的序列化不像 C++那樣,你可以輕松的自己控制每一個字節的數據,因此版本問題成了序列化 中經常遇到的一個問題。) 添加序列化到一個類型上,就意味著有一天你要讀取 這個對象的早期版本。Serializable特性生成的代碼,在對象圖的成員被添加或 者移除時會拋出異常。當你發現你自己已經要面對多版本問題時,你就需要在序 列化過程中負出更多的操作:使用ISerializable接口。這個接口定義了一些 hook用於自定義序列化你的類型。ISerializable接口裡使用的方法和存儲與默 認的序列化方法和儲存是一致的,這就是說,你可以使用序列化特性。如果什麼 時候有必要提供你自己的擴展序列化時,你可以再添加對ISerializable接口的 支持。

做一個為例子:考慮你如何來支持MyType的第2個版本,也就是添 加了另一個字段到類中時。簡單的添加一個字段都會產生一個新的類型,而這與 先前已經存在磁盤上的版本是不兼容的:

[Serializable]
public class MyType
{
 private string _label;
  [NonSerialized]
 private int _value;
 private OtherClass  _object;
 // Added in version 2
 // The runtime throws Exceptions
 // with it finds this fIEld missing in version 1.0
 // files.
 private int _value2;
}

你實現ISerializable接口來支持對這個行為的處理。ISerializable接口定義了 一個方法,但你必需實現兩個。ISerializable定義了GetObjectData()方法,這 是用於寫數據到流中。另外,如果你必須提供一個序列析構函數從流中初始化對 象:

private MyType( SerializationInfo info,
  StreamingContext cntxt );

下面的序列化構造函數演示了如何 從先前的版本中讀取數據,以及和默認添加的Serializable特性生成的序列化保 持供一致,來讀取當前版本中的數據:

using System.Runtime.Serialization;
using System.Security.Permissions;
[Serializable]
public sealed class MyType : ISerializable
{
 private string _label;
 [NonSerialized]
 private int _value;
 private OtherClass _object;
 private const int DEFAULT_VALUE = 5;
 private int _value2;
 // public constructors elided.
 // Private constructor used only by the Serialization
    framework.
 private MyType( SerializationInfo info,
   StreamingContext cntxt )
 {
  _label = info.GetString( "_label" );
  _object = ( OtherClass )info.GetValue( "_object", typeof
   ( OtherClass ));
  try {
   _value2 = info.GetInt32( "_value2" );
   } catch ( SerializationException e )
  {
   // Found version 1.
   _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 );
 }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved