5

NetDataContractSerializerを使用していくつかの.NETオブジェクトをシリアル化し、アプリケーション内でこれらのオブジェクトの状態を記憶する方法としてXMLをデータベースに保存している状況があります。最近、プロパティ名と型名のコードリファクタリングによって、このXMLデータの逆シリアル化に失敗した最初の状況に遭遇しました。

これまでのところ、NetDataContractSerializer自体で利用可能な機能を使用して逆シリアル化を制御するか、XMLを直接変換するなど、バージョンの互換性の侵害に対処する方法について、2つの異なる攻撃計画を考え出しました。私の実験と調査から、カスタムSerializationBinderを使用して別のタイプに逆シリアル化できるようですプロパティ名/タイプの変更は、ISerializableを実装するか、ISurrogateSelectorおよびISerializationSurrogateを実装してシリアル化サロゲートを作成することで対処できます。残念ながら、この優先メカニズムは機能していません。他の方法で表示できない限り、シリアル化されたデータのバージョン間を移動するサロゲートを使用しているように見えます。これは、Microsoftによる説明のつかない設計上の決定によるものです。Microsoftが提案したのは、両側で同じシリアル化を使用することです。これは、型名が変更されたり、別の名前空間またはアセンブリに移動されたりした場合に、サロゲートを使用する目的を完全に無効にします。

これを修正するには、同じNetDataContractSerializerインスタンス、または互換性のあるSurrogateSelectorで初期化された別のインスタンスを使用してください。

この説明は、シリアル化構造の他の変更に対処するとともに、カスタムバインダーを使用して型を置き換えることについて述べているMSDNの記事と矛盾します。

デシリアライズ中に、フォーマッタはバインダーが設定されていることを確認します。各オブジェクトが逆シリアル化されようとしているときに、フォーマッターはバインダーのBindToTypeメソッドを呼び出し、フォーマッターが逆シリアル化するアセンブリ名とタイプを渡します。この時点で、BindToTypeは実際に構築するタイプを決定し、このタイプを返します。

新しいタイプがSerializableカスタム属性を介した単純なシリアル化を使用する場合、元のタイプと新しいタイプはまったく同じフィールド名とタイプである必要があることに注意してください。ただし、新しいバージョンの型はISerializableインターフェイスを実装でき、その特別なコンストラクターが呼び出され、型はSerializationInfoオブジェクトの値を調べて、それ自体を逆シリアル化する方法を決定できます。

したがって、NetDataContractSerializerを機能させてV1 XMLをV2タイプに逆シリアル化できるようにするか、XMLを手動で変換する必要があります。誰かがNetDataContractSerializerのSerializationInfoがISerializableを使用するとき、またはMicrosoftが提供するものよりも優れているか、少なくともより良い説明を与えるシリアル化サロゲートを使用するときに実際に機能することを証明できれば、おそらく新しい質問を投稿して最善の方法を議論します.NETで、古いXMLを直接変換します。

UPDATE 2011-08-16: いくつかの実験の後、シリアル化された元のタイプがISerializableを実装した場合、ISerializableとシリアル化の代理手法の両方が正常に機能するようです。そうでない場合、タイプが[Serializable]属性を使用しただけの場合、オブジェクトの各フィールドが表示されます。グラフには、追加の属性の形式でいくつかの貴重な型情報がありません。

[Serializable]属性の使用例

<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
  <_stable z:Id="2">Remains the same</_stable>
  <_x003C_OldProperty_x003E_k__BackingField>23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>

ISerialzableの実装例:

<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
  <_stable z:Id="2" z:Type="System.String" z:Assembly="0" xmlns="">Remains the same</_stable>
  <_x003C_OldProperty_x003E_k__BackingField z:Id="3" z:Type="System.Int32" z:Assembly="0" xmlns="">23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>

NetDataContractSerializerとカスタムバインダーを使用してタイプを変更し、そのタイプにISerializableを実装するか、基本的にISerializalbeの役割を果たすシリアル化サロゲートを指定するサロゲートセレクターを提供することで最初の例を逆シリアル化すると、ISerializationSurrogateに空のSerializationInfoが表示されます。 .SetObjectDataメソッド。2番目の例でxmlを処理すると、SerializationInfoは正しい情報を取得しているように見え、期待どおりに機能します。

私の結論は、SerializableAttributeのみを介してシリアル化をサポートする型に対してNetDataContractSerializerによって生成されるデフォルトのXMLは、型情報が不足しているため、ISerializableまたはシリアル化サロゲート手法を使用した逆シリアル化と互換性がないということです。したがって、NetDataContractSerializableをより将来にわたって利用できるようにするには、シリアル化をカスタマイズして、このタイプ情報がXMLに含まれるようにし、ソースXMLを手動で変換せずに後で逆シリアル化をカスタマイズできるようにする必要があります。

4

1 に答える 1

2

そうです、シリアライゼーションを使用している場合は、よく考えられたデータ移行パスが必要です。あなたが言及した解決策は、逆シリアル化するコードにチェックを含めるために、私が個人的に行うことです。古いバージョンが検出された場合は、新しい形式に一致するように小さな変換を行い、必要に応じて続行します。すべてのデータが変換されると、そのコードは将来のリリースで廃止される可能性があります。

于 2011-08-16T13:24:57.300 に答える