XmlSerializer は、シリアル化された型への新しいメンバーの追加、既存のメンバーの削除などに対してより寛容であることに気付きました。
これを BinaryFormatter で実行し、古いデータを逆シリアル化しようとすると、例外がスローされました。
オプションを寛容にするために、他にどのような代替手段がありますか?つまり、例外をスローせずにデフォルト値を使用したり、それらをスキップしたりするものはありますか?
プロトコル バッファはこの点で寛容ですか?
XmlSerializer は、シリアル化された型への新しいメンバーの追加、既存のメンバーの削除などに対してより寛容であることに気付きました。
これを BinaryFormatter で実行し、古いデータを逆シリアル化しようとすると、例外がスローされました。
オプションを寛容にするために、他にどのような代替手段がありますか?つまり、例外をスローせずにデフォルト値を使用したり、それらをスキップしたりするものはありますか?
プロトコル バッファはこの点で寛容ですか?
あなたはバイナリについて言及していますが、実際、ここでBinaryFormatter
は非常に脆弱です。問題は、BinaryFormatter
タイプとフィールドに基づいていることです。XmlSerialzier
代わりに、DataContractSerializer
(3.0)などのコントラクトベースのシリアライザーが必要です。
または、バイナリの場合、protobuf-netはGoogleの「プロトコルバッファ」ワイヤ形式のC#実装ですが、.NETラインに沿って再実装されています。(注:私は著者です...)。
これは(他のデータと同様に)データコントラクトベースですが、<CustomerName>asdasd</CustomerName>
etcの代わりに、数値タグを使用して物事を識別します。それで:
[ProtoContract]
public class Customer {
[ProtoMember(1)]
public string Name {get;set;}
// ...
}
メンバーを追加すると、新しい一意の番号が付けられます。これにより、名前などに依存せずに拡張可能になります。さらに、非常に高速です; -pと同様にXmlSerializer
、予期しないものを無視し(または、予期しないデータを安全にラウンドトリップするために保存できます)、同じデフォルトのもの。既存のxml属性を使用することもできます。
[XmlType]
public class Customer {
[XmlElement(Order=1)]
public string Name {get;set;}
// ...
}
この件については一日中話すことができたので、[遅すぎる]前に黙っておいたほうがいいです。
ISerializableからクラスを継承し、カスタムGetObjectDataを定義できます。私はこれをテストしていませんが、クラスに変更が加えられたとしても、そのようなクラスはバイナリ形式から逆シリアル化できる可能性があります。
編集
これが機能することを確認しました。以下の例のようなコードを使用して、オブジェクトのシリアル化と逆シリアル化の方法を明示的に定義できます。これらのメソッドを古いバージョンのクラスで機能させるかどうかは、あなた次第です。Cerealのインスタンスをバイナリファイルにシリアル化し、クラスに変更を加え、ファイルを読み込んで逆シリアル化することで、これをテストしました。
[Serializable]
private class Cereal : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public Cereal()
{
}
protected Cereal( SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32 ( "Id" );
Name = info.GetString ( "Name" );
}
public void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue ( "Id", Id );
info.AddValue ( "Name", Name );
}
}
独自のシリアル化を行うことを強くお勧めします。これにより、言語スキームに関係なく、明確に定義されたファイル形式が得られます。
SerializableAttribute / NonSerializedAttributeおよびBinaryFormatterとSoapFormatterで使用するためのOptionalFieldAttributeを確認することもできます
... バージョン 1
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
}
... バージョン 2
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
[OptionalField]
public string field3;
}
実際、長期的にはバイナリフォーマッタが最も耐久性があることがわかりました。
優れた前方互換性を提供します。つまり、ファイルを新しいバージョンにアップグレードすると、古いデシリアライザーでは動作しなくなります。
通常、シリアル化に使用するいくつかの単純なデータ クラスを作成します。クラスを変更する必要がある場合は、OnDeserialized / OnDeserializing メソッドを実装します。これにより、データをアップグレードできます。
バイナリ フォーマッタでは、プロパティのパブリック セッターを使用する必要はありません。これは、私にとって大きな問題になることがあります。
[Serializable]
public class data
{
private int m_MyInteger;
// New field
private double m_MyDouble;
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
// some good default value
m_MyDouble = 5;
}
public int MyInteger
{
get{ return m_MyInteger; }
set { m_MyInteger = value; }
}
}
以下の記事が参考になるかと思います。また、独自のシリアライザーを作成すると言った他の人にも同意します。xsd.exe から生成されたコードよりもはるかに優れています。
以下の投稿を参照してください。