.Netを使用する場合、XmlSerializerの使用にはどのような制限がありますか?たとえば、画像をXMLにシリアル化できますか?
8 に答える
私は一般的に、XmlSerializerは単なるDTO以上のPOCOには適していないと思います。特定のXMLが必要な場合は、Xml * AttributeやIXmlSerializableルートを使用できますが、オブジェクトがかなり壊れたままになります。
いくつかの目的のために、それはまだ明白な選択です-それが制限があるとしても。しかし、単にデータを保存して再ロードするためには、BinaryFormatterが、落とし穴が少なく、はるかに簡単な選択であることがわかりました。
XmlSerializerのいくつかの煩わしさのリストを次に示します。ほとんどの場合、私はある時点で噛まれてきましたが、 MSDNで見つけた他の問題もあります。
- publicが必要で、argsコンストラクターは必要ありません
- パブリック読み取り/書き込みプロパティとフィールドのみをシリアル化します
- すべてのタイプを知っている必要があります
- 実際にはget_*とset_*を呼び出すため、検証などが実行されます。これは良いことも悪いこともあります(呼び出しの順序についても考えてください)
- 特定のルールに準拠するIEnumerableまたはICollectionコレクションのみをシリアル化します
XmlSerializerは、IEnumerableまたはICollectionを実装するクラスに特別な処理を提供します。IEnumerableを実装するクラスは、単一のパラメーターを受け取るパブリックAddメソッドを実装する必要があります。Addメソッドのパラメーターは、GetEnumeratorから返された値のCurrentプロパティから返されるものと同じタイプ、またはそのタイプのベースの1つである必要があります。
IEnumerableに加えてICollection(CollectionBaseなど)を実装するクラスには、整数を取るpublic Itemインデックス付きプロパティ(C#のインデクサー)が必要であり、整数型のpublicCountプロパティが必要です。Addメソッドのパラメーターは、Itemプロパティから返されるものと同じタイプ、またはそのタイプのベースの1つである必要があります。ICollectionを実装するクラスの場合、シリアル化される値は、GetEnumeratorを呼び出すのではなく、インデックス付きのItemプロパティから取得されます。
- IDictionaryをシリアル化しません
- 動的に生成されたアセンブリを使用します。これは、アプリドメインからアンロードされない場合があります。
パフォーマンスを向上させるために、XMLシリアル化インフラストラクチャは、指定されたタイプをシリアル化および逆シリアル化するアセンブリを動的に生成します。インフラストラクチャは、これらのアセンブリを見つけて再利用します。この動作は、次のコンストラクターを使用している場合にのみ発生します。
XmlSerializer.XmlSerializer(Type)XmlSerializer.XmlSerializer(Type、String)
他のコンストラクターのいずれかを使用すると、同じアセンブリの複数のバージョンが生成され、アンロードされないため、メモリリークが発生し、パフォーマンスが低下します。
- ArrayList[]またはList<T>[]をシリアル化できません
- 他の奇妙なエッジケースがあります
次の条件が当てはまる場合、XmlSerializerをインスタンス化して列挙型をシリアル化することはできません。列挙型がunsigned long型(C#ではulong)であり、列挙型に9,223,372,036,854,775,807より大きい値のメンバーが含まれている。
XmlSerializerクラスは、[Obsolete]としてマークされたオブジェクトをシリアル化しなくなりました。
オブジェクトを逆シリアル化するには、一時ディレクトリ(TEMP環境変数で定義されている)に書き込む権限が必要です。
- エラーに関する有用な情報を取得するには、.InnerExceptionを読み取る必要があります
XmlSerializer にはいくつかの欠点があります。
- シリアル化されるすべての型を認識している必要があります。シリアライザーが認識しない型を表すインターフェイスで何かを渡すことはできません。
- 循環参照はできません。
- オブジェクト グラフで複数回参照されると、同じオブジェクトが複数回シリアル化されます。
- プライベート フィールドのシリアル化を処理できません。
私は(ばかげて)これらの問題のいくつかを回避するために独自のシリアライザーを作成しました。そうしないでください。これは大変な作業であり、数か月後には微妙なバグが見つかるでしょう。独自のシリアライザーとフォーマッターを作成することで得られた唯一のことは、オブジェクト グラフのシリアライゼーションに関連する細かい点をより深く理解できたことです。
WCF が出てきたときにNetDataContractSerializerを見つけました。XmlSerializer が実行しない上記のすべてのことを実行します。これは、XmlSerializer と同様の方法でシリアル化を駆動します。さまざまなプロパティまたはフィールドを属性で装飾して、シリアライザーに何をシリアライズするかを通知します。作成したカスタム シリアライザーを NetDataContractSerializer に置き換えたところ、結果に非常に満足しました。強くお勧めします。
もう 1 つの問題は、XmlSerializer のコンストラクターを呼び出すと、実行時にコードがコンパイルされ、逆シリアル化を行うコードを含む一時 DLL (%temp% フォルダー内) が生成されることです。
次の行を app.config に追加すると、コードを見ることができます。
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="4"/>
</switches>
</system.diagnostics>
初めてクラスをシリアル化するときは、かなりの時間がかかり、コンパイルしてディスクに書き込むためのアクセス許可を持つコードが必要になります。
これを回避する方法は、VS 2005+ に付属の sGen.exe ツールを使用してこれらの DLL をプリコンパイルすることです。
制限があるかどうかはわかりません。しかし、.NET 1.1のXmlSerializationにメモリリークのバグがあったため、この問題を回避するには、キャッシュシリアライザオブジェクトを作成する必要がありました...実際、この問題かどうかはわかりません.net2.0以降で修正されました...
私が考えることができる1つの制限は、XmlSerializationがオプトアウトであるということです。つまり、シリアル化したくないクラスのプロパティは、[XmlIgnore]で装飾する必要があります。すべてのプロパティがオプトインされているDataContractSerializerとは対照的に、包含属性を明示的に宣言する必要があります。これが良い記事です。
画像またはそのバイナリ配列は、XmlSerializerによってbase64でエンコードされたテキストとしてシリアル化されます。
理論的には、作成するクラスはすべてXmlSerializerを介してフィードできます。ただし、パブリックフィールドにしかアクセスできないため、クラスは正しい属性(XmlAttributeなど)でマークする必要があります。基本的なフレームワークでも、すべてがXmlSerializerをサポートしているわけではありません。たとえば、System.Collections.Generic.Dictionary<>。
たとえば、IDictionary インターフェイスを実装するクラスをシリアル化することはできません。
コレクションの場合、単一の引数を取るAddメソッドが必要です。特にxmlではなくテキスト形式が必要な場合は、JSONを試してみてください。私は.NET用にJsonExSerializerを開発しましたが、他にもhttp://www.json.orgで入手できます。