6

メインクラスが属性でマークされている最適化なしで、binaryFormatterを使用してアプリケーションデータをファイルストリーム(「data.oldformat」という名前のファイルなど)にシリアル化する古いアプリケーションを操作する必要があります

<serializable()>public MainClass
....... 
end class

そしてシリアルコード

dim b as new binaryformatter
b.serialize(mystream,mymainclass)

シリアライゼーション/デシリアライゼーション プロセスを最適化するために、クラスに ISerializable インターフェイスを実装させ、最適化されたシリアライゼーション ルーチンをいくつか書きました。

<serializable()>public MainClass
       implements ISerializable
....... 
end class

最適化は非常にうまく機能しますが、下位互換性のために古いファイル内のデータを再取得する方法を見つけなければなりません。

どうやってやるの??

ピエルルイジ

4

5 に答える 5

4

stmaxには優れた答えがありますが、SerializationEntry.GetEnumerator()代わりにを使用するこのように実装しtry/catchます。この方法はよりクリーンで、大幅に高速です。

public MainClass(SerializationInfo info, StreamingContext context) {
    int version = 0;
    foreach (SerializationEntry s in info)
    {
        if (s.Name == "version") 
        {
            version = (int)s.Value;
            break;
        }
    }

    switch (version) {
      case 0:
        // deserialize "old format"
        break;
      case 1:
        // deserialize "new format, version 1"
        break;
      default:
        throw new NotSupportedException("version " + version + " is not supported.");
    }
}

私は .FirstOrDefault() を使用する LINQ バージョンを好みますが、SerializationInfo は IEnumerable を実装していません。奇妙なことに、古い IEnumerable インターフェイスを実装していません。

于 2011-09-28T18:47:51.340 に答える
4

ISerializable インターフェイスを既に実装しているため、必要なコンストラクターも既に追加している可能性があります。

public MainClass(SerializationInfo info, StreamingContext context) {}

コンストラクターに渡された情報オブジェクトを使用して、シリアル化されたファイルからデータを取得できます。デフォルトでは (つまり、ISerializable が実装されていない場合)、シリアル化中にフィールド名が識別子として使用されます。したがって、古いクラスにフィールド「int x」があった場合、次を使用してこれを逆シリアル化できます。

this.x = info.GetInt32("x");

新しいバージョンの場合、通常、シリアル化中に次のように「バージョン」エントリを追加します。

public void GetObjectData(SerializationInfo info, StreamingContext context) {
  info.AddValue("version", 1);
  info.AddValue("othervalues", ...);
}

逆シリアル化中に、このバージョン エントリを確認し、それに応じて逆シリアル化できます。

public MainClass(SerializationInfo info, StreamingContext context) {
    int version;
    try {
       version = info.GetInt32("version");
    }
    catch {
       version = 0;
    }

    switch (version) {
      case 0:
        // deserialize "old format"
        break;
      case 1:
        // deserialize "new format, version 1"
        break;
      default:
        throw new NotSupportedException("version " + version + " is not supported.");
    }
}

私はそのコードをコンパイルしていません。タイプミスが含まれている可能性があります。

それが役立つことを願っています。

于 2010-04-10T16:03:19.317 に答える
0

今までと同じことをやってみる

BinaryFormatter b = new BinaryFormatter();
MainClass a = b.DeSerialize(mystream) as MainClass;

ISerializable を実装しても、元のクラスは変更されませんでした。基本的には、いくつかのメソッドを追加しただけです。

于 2010-04-10T15:54:59.860 に答える
0

オブジェクトをシリアル化するときに、追加の Version フィールドを追加します (これにより、オーバーヘッドが大きくなりません)。次に、GetObjectData メソッドで、最初にバージョン フィールドを取得し、これが存在するかどうかに基づいて (SerializationException をキャッチして) 古い方法または新しい方法で逆シリアル化します。古い方法では、すべてのデータをシリアル化しただけなので、すべてのフィールドに対して Get... を呼び出すことができるはずです。

于 2010-04-10T15:58:32.873 に答える
0

以前のコードが機能するはずです。例外はありますか?新しいコンストラクターを使用してみてください:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
于 2010-04-10T16:00:02.097 に答える