2011-03-21 41 views
15

古いバージョンのアプリケーションで「SomeClass」を逆シリアル化しようとしています。私は例外の下でこれを得る逆シリアル化の逆シリアル化

System.Runtime.Serialization.SerializationException:ObjectManagerが無効な数のフィックスアップを見つけました。これは、通常、Formatterの問題を示します。私はバージョン0.9をシリアライズし、バージョン0.8を使用してデシリアライズしようとき

逆シリアル化は、例外がスローされます。私はOptionalField属性がトリックをするだろうと思ったが、そうしなかった。私は、以前のバージョンは何でも彼らができるデシリアライズすることができるようにFooのオブジェクトに多くの状態を追加する必要がありますどのように、バージョン0.8を変更することができないことを考えると

// Version 0.8 
[Serializable()] 
class Foo{ 
    Bar b; 
} 

// Version 0.9 
[Serializable()] 
class Foo{ 
    Bar b; 
    [OptionalField] 
    Zoo z; 
} 

すべてのポインタは本当に感謝されます。

更新1 バーとZooは、シリアライズ可能で、ハッシュテーブルやその他のシリアライズ可能なものを含む他のクラスです。これらのクラスではすべてがシリアライズ可能です。 また、ストラットはありません。

+0

フィールドがオプションかどうかはここでは無関係です。事実、シリアル化はAFAIKのバージョン間では機能しません。それはもちろん、メンバーを追加することはできないと言っているわけではありませんが、例えば、慣習的な型を定義し、既存のものと直列化された項目をデシリアライズすることはできません。 '、と思います。 –

+0

kareph、実際のタイプの「動物園」は何ですか?私はいくつかの型(配列)が正しく動作しなかったことを覚えています。 –

+0

バイナリシリアル化ではなくxmlシリアル化を使用しますか?それはよりバージョンセーフです。 – code4life

答えて

26

まず、決して使用しないでくださいCLRのシリアライズ機能のSoap Serializationを試しclassesにあればstructsを変換しますストレージ。私たちは通常、間違いを一度作り、オブジェクトをBLOBデータベースフィールドに入れ、私たちが賢明だと考えて背中を撫でます。そしてCLRがパッチを取得するか、アセンブリがバージョンを変更してしまい、あなたがうんざりしてしまいます。そうしないでください。

public sealed class CustomBinder : SerializationBinder { 

    public override Type BindToType(string assemblyName, string typeName) { 

     Type typeToDeserialize = null; 

     if (typeName.IndexOf("SomeType") != -1) { 
      typeToDeserialize = typeof(Foo.Bar.Bax.NewType); 
     } 
     else if (typeName.IndexOf("SomeOtherType") != -1) { 
      typeToDeserialize = typeof(Foo.Bar.Bax.SomeOtherNewType); 
     } 
     else { 
      // ... etc 
     } 

     return typeToDeserialize; 
    } 
} 

設定し、あなたが前に使用しているフォーマッタのBinderプロパティ:

あなたはまだそれをしたい場合は、問題を管理するための最良の方法は、次のようになり、独自のSerializationBinder作成することです。デシリアライズしてデフォルトに優先させます。

ここではドロップインソリューションを提供していないことに注意してください。この問題の解決方法をお勧めします。いったい何をやっていても、protobufのような他のシリアライゼーション技術を調べたり、自分のことを書いたりしてください。いずれにしても、長期的なシリアル化サポートのためにCLRに決して頼るべきではありません。

+2

「NEVER」コメントはXMLシリアル化にも適用されますか? DataContractとDataMemberを使用すると、生成された構造を適切に制御できることがわかります。あなたの意見を聞くことに興味がありますか? – paul

+0

ただし、バイナリシリアライザは長期的なシリアライゼーションには適していません。これは、クライアント/サーバアプリケーションなどで、ワイヤを介してバイトをポンピングするのに最適です。たとえば、WebFormsはそれを使用します。 – Sebazzz

2

これを行う方法の1つは、最新のバージョンを使用してオブジェクトをデシリアライズすることができるように、バージョン管理されたオブジェクトを持つことです。それがうまくいかなかったら、成功するまでバージョンを元に戻してください。オブジェクトを取得したら、それをオブジェクトの最新バージョンに更新し、データがないフィールドにはデフォルト値を使用します。

+0

アプリケーションをダウングレード(ロールバックの結果)すると、(データが失われているのではなく)不足しているフィールドがあります。とにかくあなたが言っていることは、それがすべきことです。 – karephul

+0

私はそれがCプログラマが何をするために使用するのか知っています。私は抽象度が非常に高いレベルでプログラミングしていると思っていましたが、これは標準的な問題かもしれません。あなたの洞察に感謝します。 – karephul

0

optional fieldの属性がこのトリックを完了しているはずです。シリアライズしようとしている実際のクラスを投稿できますか?

あなたはまずこれらの事を試みることができる -

が長期的に似ている何のために代わりbinary serilization

+0

投稿を更新しました。 – karephul

+0

あなたは石鹸のシリアル化を試しましたか? –

4

各バージョンのコンストラクタが互換性がある場合(例:パラメータなしまたは両方のバージョンのFoo(Bar b)コンストラクタは、あなたのストリームをデシリアライズする前に

BinaryFormatter formatter = new BinaryFormatter(); 
formatter.AssemblyFormat = Formatters.FormatterAssemblyStyle.Simple; 

を呼び出すことができます)があります。

3

「遅すぎる前に」この問題を調査している人々の助言として、私はBinaryFormatterで永続することを強くお勧めします。同期している2つのアプリケーションドメイン間の一時的な転送はOKですが、それはIMOに関するものです。これらの問題を持たない他のシリアル化ツールが存在します。バイナリに関しては、protobuf-netはかなり妥当なオプションです - 苦痛なしに追加/削除/名前変更などが可能です。

関連する問題