C#のシリアライズについてのまとめ
privateメンバをシリアライズ可能なのはバイナリでシリアライズする場合のみであり、jsonやxmlを使う場合はpublicメンバのみシリアライズされる
DataContractSerializerを使用する場合はDataMember属性を使用することでprivateメンバをシリアライズできる
むしろ、「jsonやxmlでprivateメンバをシリアライズできない」という情報はどこから出てきた?このページには書かれていないが…
バイナリでのシリアライズはセキュリティ的に推奨されない
Serializable属性を対象のクラスに付加し、System.Runtime.Serialization.Formatter のインスタンスを使用するシリアライズが「基本的なシリアライズ」とされている
「基本的なシリアライズ」は、データコントラクトを使用したシリアライズとどのように異なる?
「基本的なシリアライズ」と対比されているのは、ISerializable インターフェイスを使用した「カスタムのシリアライズ」
属性を SerializableAttribute 型に適用すると、すべてのプライベート フィールドとパブリック フィールドが既定でシリアル化されます。
publicもprivateもデフォルトでシリアライズされる(!)
シリアライズしたくないメンバにはNonSerialized属性を付ける
BinaryFormatter や SoapFormatter を使用したシリアライズ
Serializable属性が必須
対象クラスはprivateでもいい
privateメンバもシリアライズされる
XmlSerializerを使用したシリアライズ
属性不要
対象クラスはpublicにする必要がある
public メンバのみシリアライズされる
なお、BinaryFormatterおよびSoapFormatterは、シリアライズされるオブジェクトが自動実装プロパティ(C#、VB)を含んでいる場合でもバッキングフィールドの値を適切にシリアライズします。
BinaryFormatter や SoapFormatter を使用したシリアライズは、.NET5以降では非推奨
BinaryFormatter.Deserializeメソッドは、信頼できない入力に対して、決して安全ではありません。
Microsoftが安全でないと考えるシリアライゼーションライブラリはこれだけではない。以下のものは、危険性は高くないものの、無制限にポリモーフィックなデシリアライゼーション(deserialization)が懸念されるため、使用は回避するべきだ。
SoapFormatter
LosFormatter
NetDataContractSerializer
ObjectStateFormatter
詳しい理由はともかく、使用しない方が無難
.NET には、さまざまなシリアル化シナリオに合わせて最適化できる 3 つの主なシリアル化テクノロジがあります。
データ コントラクトのシリアル化
XML シリアル化
ランタイム シリアル化 (バイナリおよび SOAP)
このカテゴリはおそらく非推奨
シリアライズ対象がIDictionaryを含んでいる場合、XmlSerializerは使用できず、DataContractSerializerなどを使用する必要がある
XmlSerializerでシリアライズしようとすると例外が出る
シリアル化したいメンバ(フィールドやプロパティ)には、DataMemberAttribute属性を適用します。DataMemberAttribute属性はパブリックメンバだけでなく、プライベートメンバにも適用できます。DataMemberAttribute属性が適用されていないメンバは、シリアル化されません。
補足:DataContractSerializerクラスは、DataContractAttribute属性が適用されていない型でもシリアル化することもできます。その場合は、XmlSerializerクラスと同じように、パブリックメンバだけをシリアル化します。シリアル化できる型については、「データ コントラクト シリアライザーでサポートされる型」で説明されています。
DataContract属性を明示的に適用した場合、DataMemberを適用しないメンバはpublicであってもシリアライズされない
復元されたTestClassオブジェクトのMessageプロパティは、Nothing(C#では、null)になります。なぜなら、DataContractSerializerは逆シリアル化する時にTestClassクラスのコンストラクタを呼び出さないからです。
シリアライザによってコンストラクタ呼び出しの有無が異なる
XmlSerializerやBinaryFormatterはコンストラクタ呼び出しあり、DataContractSerializerはコンストラクタ呼び出しなし
Unityでは逆シリアライズ時にコンストラクタが呼び出されるっぽい
XmlSerializerとDataContractSerializerの比較についてまとめられている
パフォーマンスはDataContractSerializerのほうが若干高い
DataContractSerializerはシリアライズするメンバを明示的に指定する方式 (opt-in) とのことだが、デフォルトの挙動はどちらも opt-out なのでは?
XmlSerializerはopt-inにすることができない?
privateメンバをシリアライズできない?
DataContractSerializerはHashTableやDictionaryをシリアライズできる
XmlSerializerでもシリアライズする方法はあるが、わりと面倒
コンストラクタの呼び出し有無が異なる
XmlSerializer は出力されるXMLのフォーマットを詳細に指定できる
CONSIDER supporting the XML serialization instead of or in addition to data contract serialization if you need more control over the XML format that is produced when the type is serialized.
This may be necessary in some interoperability scenarios where you need to use an XML construct that is not supported by data contract serialization, for example, to produce XML attributes.
型のシリアライズ時に生成される XML 形式をより詳細に制御する必要がある場合は、データコントラクトの代わりに、またはそれに加えて、XML シリアライズをサポートすることを検討してください。
これは、データコントラクトサポートされていない XML 構成を使用して XML 属性を生成する必要がある場合など、一部の相互運用性シナリオで必要になる場合があります。
DataContractSerializerは上位下位互換性が強化されている
ただし開発者が適切に実装する必要がある
上記より、XMLのフォーマットを詳細に指定する必要がない場合はDataContractSerializerを使用するのがよさそう
型を部分信頼で使用する場合は、型のデータ メンバーをパブリックにすることを検討してください。 完全な信頼では、データ コントラクト シリアライザーでパブリックではない型とメンバーのシリアル化と逆シリアル化を行うことが可能ですが、部分信頼の場合、パブリック メンバーのみをシリアル化および逆シリアル化できます。
部分信頼の場合はDataMember属性を使用してもprivateメンバをシリアライズできない?
一般的に、インターネット アプリケーションでは、悪意による損害を防ぐため、重要なシステム リソースへの直接アクセスを制限する必要があります。 既定では、HTML およびクライアント側のスクリプト言語では、重要なシステム リソースにアクセスできません。
データ コントラクト は、サービスとクライアントの間の正式な取り決めであり、交換されるデータが抽象的に記述されています。
すべての .NET Framework プリミティブ型 (整数や文字列など) およびプリミティブ型として扱われる特定の型 (DateTime や XmlElementなど) は、準備なしでシリアル化できるため、既定のデータ コントラクトを持つと見なされます。
すべてのパブリック フィールドと、パブリック get メソッドおよび set メソッドを持つプロパティは、IgnoreDataMemberAttribute 属性をそのメンバーに適用しない限りシリアル化されます。
既定の動作を変更するには、DataContractAttribute 属性と DataMemberAttribute 属性を型とメンバーに適用します。
DataContract属性を使用しなくても、DataContractSerializerの対象にすることは可能
DataContract属性を使用するのは、NamespaceやNameなどのプロパティをオーバーライドしたいとき
既定では、データ コントラクトの名前は、DataContractAttribute が適用される型の名前になります。 ただし、理由によっては、この既定の名前を変更することができます。
また、DataContract属性を使用するとDataMember属性が付いていないpublicメンバーがシリアライズされなくなるため、明示的にシリアライズ対象を指定したい場合にも使う
プライベートなフィールドまたはプロパティに DataMemberAttribute を適用できます。 メンバーによって返されるデータ (プライベートであっても) はシリアル化および逆シリアル化されるため、悪意のあるユーザーまたはプロセスによって表示または傍受される可能性があることに注意してください。
この記述から、privateメンバが通常シリアライズの対象にならないのはセキュリティを考慮しているためであり、開発者が明示的に指定すれば問題なくシリアライズできることが分かる
DataMember属性を使用するのは、privateメンバをシリアライズしたいときや、プロパティをオーバーライドしたいとき
属性が DataMemberAttribute 適用されているプロパティには、 get と set 両方のフィールドが必要です。
シリアライズでget, 逆シリアライズでsetを使用する
設計上 getのみ保持する必要があるプロパティ (コレクションを返すプロパティなど) をシリアル化するには、代わりにバッキング フィールドに適用することを検討してください。
シリアライズはprivateメンバを対象とすることができるため、public int Hoge { get { return _hoge; } } のようなプロパティがある場合は _hoge をシリアライズすればいい
DatContract属性を明示的に適用していなくても、サポートされている型(つまり暗黙的にDataContract属性が適用されている型)であればDataContractSerializerでシリアライズ可能