クラスに新しいフィールドを追加するバイナリシリアル化 - 機能しますか?
-
29-09-2019 - |
質問
バイナリシリアル化を使用して.NET 2.0のリモートを介して通信するクライアントとサーバーアプリケーションがあります。
データ転送オブジェクトのインターフェイスの1つに小さな変更が加えられており、実装クラス、まあ、一連の文字列フィールドが追加されました。
サーバーアプリケーションの新しいバージョンを再展開する場合、古いクライアントは機能し続けますか?
インターフェイスと直接実装から削除されていないので、彼らはそうするだろうと思いますが、私にはわかりません。
それはおそらく別の質問に要約されます - フィールドを初期化することでこのような状況を処理するのに十分なバイナリ脱派の「賢い」です。 ?
解決
新しいプロパティに属性を追加できます。 OptionalField
. 。属性がなければ、Deserializerはシリアル化されたデータを更新された定義に変換することができません。属性は、Deserializerが「欠落している」データを優雅に処理できるようにすることです。
新しいプロパティのデフォルト値を設定する場合は、それの適切なデータが敏感にされていない場合、 IDeserializationCallback
インターフェイスし、結果のメソッドでデフォルト値を設定します。
他のヒント
おそらく例外をスローするでしょう。 ISerializable
独自の方法を使用してバージョンを実装します GetObjectData
...これにより、シリアル化されるデータに対するより厳しい制御が得られます...これが例です
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
public class MyFooBar : ISerializable{
private float _fVersion = 1.0;
public MyFooBar(SerializationInfo info, StreamingContext context) {
this._fVersion = info.GetSingle("FooBarVersionID");
if (this._fVersion == 1.0F) bOk = this.HandleVersionOnePtZero(info, context);
if (!bOk) throw new SerializationException(string.Format("MyFooBar: Could not handle this version {0}.", this._fVersion.ToString()));
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
public void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue("FooBarVersionID", this._fVersion);
if (this._fVersion == 1.0F) {
// Bool's...
info.AddValue("FooBarBool", FooBarBool);
// etc... for Version 1.0
}
if (this._fVersion == 1.1F){
// etc... for Version 1.0
}
}
}
以下に示すように、シリアル化/脱必要性のある場合は、このコンテキストでmyfoobarを使用します
public bool Deserialize(string sFileName) {
bool bSuccessful = false;
//
if (!System.IO.File.Exists(sFileName)) return false;
fuBar = new MyFooBar();
//
try {
using (FileStream fStream = new FileStream(sFileName, FileMode.Open)) {
try {
BinaryFormatter bf = new BinaryFormatter();
fuBar = (MyFooBar)bf.Deserialize(fStream);
bSuccessful = true;
} catch (System.Runtime.Serialization.SerializationException sEx) {
System.Diagnostics.Debug.WriteLine(string.Format("SERIALIZATION EXCEPTION> DETAILS ARE {0}", sEx.ToString()));
bSuccessful = false;
}
}
} catch (System.IO.IOException ioEx) {
System.Diagnostics.Debug.WriteLine(string.Format("IO EXCEPTION> DETAILS ARE {0}", ioEx.ToString()));
bSuccessful = false;
}
return (bSuccessful == true);
}
これを2.0+以上で行うためのより厄介な方法がありますが、私はこの方法を好みます。