web-dev-qa-db-ja.com

DataContractSerializerがコンストラクタを呼び出さないのですか?

私は完全に不可能であると想定している奇妙なことに気づきました。オブジェクトを逆シリアル化するとき、DataContractSerializerはコンストラクターを呼び出しません

このクラスを例にとります:

[DataContract]
public class Book
{
    public Book()
    { // breakpoint here
    }

    [DataMember(Order = 0)]
    public string Title { get; set; }
    [DataMember(Order = 1)]
    public string Author { get; set; }
    [DataMember(Order = 2)]
    public string Summary { get; set; }
}

そのクラスのオブジェクトを逆シリアル化しても、ブレークポイントにヒットしません。それがこのオブジェクトの唯一のコンストラクタであるため、私はそれがどのようにして可能であるのかまったくわかりません!

DataContract属性が原因で、おそらく追加のコンストラクタがコンパイラによって生成されたと思いましたが、リフレクションではそれを見つけることができませんでした...

だから、私が知りたいのはこれです:コンストラクタを呼び出さずにクラスのインスタンスを作成するにはどうすればよいですか?

注:逆シリアル化の開始時にOnDeserializing属性を使用してオブジェクトを初期化できることを知っています。これは私の質問の主題ではありません。

96
Thomas Levesque

DataContractSerializerBinaryFormatterと同様)はanyコンストラクタを使用しません。空のメモリとしてオブジェクトを作成します。

例えば:

    Type type = typeof(Customer);
    object obj = System.Runtime.Serialization.
        FormatterServices.GetUninitializedObject(type);

逆シリアル化プロセス(または必要に応じてコールバック)が完全に初期化することが前提です。

132
Marc Gravell

この動作なしでは実現できないシナリオがいくつかあります。次のことを考えてください。

1)新しいインスタンスを「初期化」状態に設定する1つのコンストラクターを持つオブジェクトがあります。次に、そのインスタンスでいくつかのメソッドが呼び出され、「処理済み」状態になります。 「処理済み」状態の新しいオブジェクトを作成するのではなく、インスタンスを逆シリアル化/逆シリアル化したい場合。

2)プライベートコンストラクターといくつかの静的プロパティを使用してクラスを作成し、許可されたコンストラクターパラメーターの小さなセットを制御しました。これで、それらをシリアライズ/デシリアライズできます。

XmlSerializerは期待どおりの動作をします。デフォルトのコンストラクタが必要なため、XmlSerializerでいくつかの問題が発生しました。これに関連して、プライベートプロパティセッターを使用することが理にかなっている場合があります。ただし、XmlSerializerでは、シリアル化/逆シリアル化するために、プロパティのパブリックゲッターとセッターも必要です。

DataContractSerializer/BinaryFormatterの動作は、シリアル化中にインスタンスの状態を一時停止し、逆シリアル化中に再開するようなものだと思います。つまり、インスタンスは「構築」されず、以前の状態に「復元」されます。

すでに述べたように、[OnDeserializing]属性を使用すると、シリアル化されていないデータを同期させることができます。

3
BasvdL