2009-03-31 14 views
11

ビルトインにBinaryFormatterベースの.NETシリアル化の欠陥は何ですか? (パフォーマンス、柔軟性、制限)組み込みのBinaryFormatterベースの.Netシリアル化の欠点は何ですか?

可能な場合は、いくつかのコードを使用して答えを同行してください。

例:[Serializableを]属性で修飾またはISerializableインターフェイスを実装する必要がありますシリアライズさ

カスタムオブジェクト。

あまり明白な例:

匿名型をシリアル化することはできません。

答えて

16

あなたはBinaryFormatter意味場合:

  • がフィールドに基づいている、非常にバージョン偏狭です。
  • (メタデータがで燃焼する)組立固有である
  • 新しい分野に向けた非常に友好的ではありません
  • 他のプラットフォームで(だけでも、changing it to an automatically implemented property
  • クロス互換性がありませんプライベートな実装の詳細を変更し、それが壊れますMS/.NETの特定(及び具体的な可能性.NET版)
  • は光フレームワーク上で動作しない難読化、安全
  • は、特に高速ではないか、小さな出力されません(CF?/ Silverlightのです)
  • 私は、Googleの「プロトコルの(無料)の実装を書い含め、この地域に多くの時間を費やしてきたあなたは(通常event Sを経由して)

を期待していなかったものを引き込むの憂鬱な癖を持っていますバッファ "シリアル化API for .NET; protobuf-net

これは:

+0

yerp私はBinaryFormatterに基づくシリアル化を意味していました... –

2

は、任意のランダムなオブジェクト、it's very difficult to prove whether it really is serializableを考えます。

+1

シリアル化の難しい問題は、 'Foo'オブジェクトが' Bar'によっても参照されるオブジェクトへの参照を含んでいて、 'Foo'がその参照について' Bar'を求める手段を持たない場合、 'Bar'の言及は、' Foo'の状態の本質的な側面を形作っているかもしれませんが、シリアライザーがそれを知る方法はありません。 – supercat

1

あなたがシリアライズしているオブジェクトを変更した場合は、シリアル化されてきたし、保存されているすべての古いデータが壊れています。データベースやXMLに保存した場合、古いデータを新しいものに変換する方が簡単です。

+1

これは厳密には変更が破られていることではありません... http://msdn.microsoft.com/en-us/library/system.runtime.serialization.optionalfieldattribute.aspx –

2

データのバージョン管理は属性によって処理されます。バージョン管理について心配していないなら、これは問題ありません。もしあなたなら、それは大きな問題です。

属性スキームの問題は、多くの簡単なケース(新しいプロパティの追加など)ではかなり滑らかですが、別の新しい列挙型で2つの列挙型の値を置き換えようとするとかなり急速に壊れます(または長寿命永続データに付随する任意の数の一般的なシナリオ)。

問題の詳細を詳しく説明できます。あなたが必要とする場合は、あなた自身のシリアライザを書くことは簡単ですね...

1

異なるフレームワーク(Say 1.0,1.1,3.5)または異なるCLR間でオブジェクトを前後にシリアル化することはできませんXMLの実装(Mono)は、この目的にはさらに優れています。

+0

または別のバイナリ形式。私の答えを参照してください... –

1

心に来たもう一つの問題:

クラスは、一般的な実行時フォーマッタとは完全に異なる場所に配置されているのXmlSerializer。また、使用方法は非常に似ていますが、XmlSerializerはIFormatterインターフェイスを実装していません。 BinaryFormatter、XmlSerializer、またはカスタムフォーマッタの間で実行時にシリアル化フォーマッタを入れ替えるだけのコードを追加することはできません。シリアライズされ

+0

XmlSerializerは、ランタイムシリアライザとフォーマッタとはまったく異なる目的を持っています。あなたは交換したくないでしょう。 –

1

タイプ は[Serializableを] 属性で修飾する必要があります。

あなたはクラスの変数を意味している場合、あなたは間違っています。パブリック変数/プロパティがやや明瞭で1パフォーマンスは、オブジェクトのシリアル化のためにかなり貧弱であるということである自動にシリアライズさ

+0

私は実際に彼がクラスそのものを意味していると思われますが、ISerializableを実装するオプションもあるので、それでも間違っています。たとえそれが正しければ、それはまったく悪いことではないと私は思います。 –

+0

申し訳ありませんが、私はクラス自体がその例を展開することを意味します –

+0

それはAPIに依存します。 BinaryFormatter/SoapFormatterはフィールド(publicまたはprivate)に対して機能します。 XmlSerializerはパブリックメンバー(フィールドまたはプロパティ)に対して機能します。 DataContractSerializerは、[DataMember]とマークされたメンバーに対して(理想的に)機能します。 –

0

です。私のマシンで10万オブジェクトシリアライズとデシリアライズする

Example

時間:単一のintフィールドを持つオブジェクトをシリアライズこの単純な例では

Time Elapsed 3 ms 
Full Serialization Cycle: BinaryFormatter Int[100000] 

Time Elapsed 1246 ms 
Full Serialization Cycle: BinaryFormatter NumberObject[100000] 

Time Elapsed 54 ms 
Full Serialization Cycle: Manual NumberObject[100000] 

は手でそれを行うよりも20倍遅くかかります。確かに、シリアライズされたストリームにはいくつかの型情報があります。しかし、これは20倍の減速を説明するものではありません。

0

:オープン文書化標準の.NETのすべてのバージョンに

  • 作品(マイクロFramework上でテストされていない注意点)があります最後の答え。パフォーマンスはかなり悪いです。 私のチームのコーダーは、標準C++からC++/CLIへのシミュレーションの変換を終了しました。 C++の下では手作業で永続化機構を書いていましたが、これは合理的にうまく機能しました。古い永続化メカニズムを書き直すのではなく、シリアライゼーションメカニズムを使用することにしました。
    メモリフットプリントが1/2と1ギガの古いシミュレーションと、他のオブジェクトへのポインタと実行時のオブジェクトのポインタを持つほとんどのオブジェクトは、1分未満で約10〜15メガバイトのバイナリファイルを保持します。ファイルからの復元は同等でした。
    同じデータファイル(サイドバイサイドで実行)を使用すると、C++/CLIの実行パフォーマンスはC++の約2倍です(永続化(新しいバージョンでのシリアライゼーション)まで)Writng outには3〜5分かかります読み込みには10から20が必要です。シリアライズされたファイルのファイルサイズは、古いファイルの約5倍です 基本的に、読み込み時間は19倍、書き込み時間は5倍になります。これは容認できないものであり、我々はこれを是正する方法を模索している。

    バイナリファイルを調べると、私はいくつかのことを発見しました。1.タイプとアセンブリのデータは、すべてのタイプについてクリアテキストで書かれています。これは、空間的に非効率的です。 2.すべてのタイプのすべてのオブジェクト/インスタンスには、拡張された型/アセンブリ情報が書き出されています。私たちの手持ちのメカニックでやったことの一つは、知られているタイプのテーブルを書くことでした。書面で型を発見したので、この表の型を調べました。存在しない場合は、型情報とインデックスが割り当てられたエントリが作成されます。次に、型infを整数として渡しました。 (タイプ、データ、タイプ、データ)この「トリック」はサイズを大幅に削減します。これは、データを2回通す必要があるかもしれませんが、オンザフライのプロセスが開発される可能性があります。それは、テーブルに追加するだけでなく、ストリームにプッシュするだけでなく、ストリームからのレスソレーションの注文。

    私は、このように最適化するためにコアのシリアライズを再実装したいと考えていましたが、クラスは密封されています!我々はまだそれをジェリーリグにする方法を見つけるかもしれない。

  • 0

    別の状況では、BinaryFormatterで例外がスローされます。

    [Serializable] 
    class SerializeMe 
    { 
        public List<Data> _dataList; 
        public string _name; 
    } 
    
    [Serializable] 
    class Data 
    { 
        public int _t; 
    } 
    

    今日、SerializeMeがシリアル化されるとします。明日、我々はもはやクラスDataが必要なくなり、それを削除することを決定する。したがって、Listを削除するためにSerializeMeクラスを変更します。現在、古いバージョンのSerializeMeオブジェクトを逆シリアル化することは不可能です。

    解決策は、余分なクラスを適切に無視するカスタムBinaryFormatterを作成するか、クラスDataを空の定義で保持することです(Listメンバーを保持する必要はありません)。