2009-07-02 14 views
84

Ich habe gerade etwas verrücktes realisiert, was ich für absolut unmöglich gehalten habe: Beim Deserialisieren eines Objekts ruft der DataContractSerializer den Konstruktor nicht auf!DataContractSerializer ruft meinen Konstruktor nicht auf?

diese Klasse Nehmen wir zum Beispiel:

[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; } 
} 

Wenn ich ein Objekt dieser Klasse deserialisiert wird der Breakpoint nicht getroffen. Ich habe absolut keine Ahnung, wie es möglich ist, da es der einzige Konstruktor für dieses Objekt ist!

ich davon aus, dass vielleicht ein zusätzlicher Konstruktor vom Compiler aufgrund des DataContract Attributs generiert wurde, aber ich kann es nicht durch Reflexion finden ...

Also, was ich weiß, möchte, ist dies: Wie könnte eine Instanz meiner Klasse erstellt werden, ohne dass der Konstruktor aufgerufen wird?

HINWEIS: Ich weiß, dass ich das OnDeserializing Attribut verwenden kann, um mein Objekt zu initialisieren, wenn Deserialisierung beginnt, das ist nicht das Thema meiner Frage.

+3

oder die "OnDeserialized", wenn das Objekt deserializing getan wird, um die fehlenden Felder auszufüllen. –

+1

Diese Frage ist mir auch in den Sinn gekommen: http://stackoverflow.com/questions/178645/how-does-wcf-deserialization-instantiate-objects-without-calling-a-constructor –

Antwort

118

DataContractSerializer (wie BinaryFormatter) verwendet keine jeder Konstruktor. Es erstellt das Objekt als leerer Speicher.

Zum Beispiel:

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

Die Annahme ist, dass die Deserialisierung (oder Rückrufe falls erforderlich) es vollständig initialisieren wird.

+82

Das ist CHEATING !! – Cheeso

+0

Der Konstruktor sollte beim Deserialisieren nicht aufgerufen werden. Wenn es aufgerufen wurde, dann 1) Was ist mit den Ressourcen, die Sie im Konstruktor erstellt haben? Sie werden undicht! 2) Sie initialisieren das Objekt zweimal, einmal im Konstruktor und einmal mit den deserialisierten Werten. – Dudu

+1

@Dodu a: das wird kein Leck verursachen b: das (Aufruf des Ctor) ist, wie viele Serialisierer arbeiten; Jeder Weg ist in der Regel gut als Protokoll, wie das Verhalten verstanden wird und Designer –

3

Es gibt einige Szenarien, die ohne dieses Verhalten nicht möglich wären. Denken Sie an Folgendes:

1) Sie haben ein Objekt mit einem Konstruktor, der die neue Instanz in einen "initialisierten" Zustand versetzt. Dann werden einige Methoden für diese Instanz aufgerufen, die sie in einen "verarbeiteten" Zustand bringen. Sie möchten keine neuen Objekte mit dem Status "processed" erstellen, aber Sie möchten die Instanz weiterhin serialisieren/deserialisieren.

2) Sie haben eine Klasse mit einem privaten Konstruktor und einigen statischen Eigenschaften erstellt, um einen kleinen Satz zulässiger Konstruktorparameter zu steuern. Jetzt können Sie sie noch serialisieren/deserialisieren.

XmlSerializer hat das von Ihnen erwartete Verhalten. Ich hatte einige Probleme mit dem XmlSerializer, weil es einen Standardkonstruktor benötigt. In diesem Zusammenhang macht es manchmal Sinn, private Grundstückssiedler zu haben. Aber der XmlSerializer benötigt auch einen öffentlichen Getter und Setter für Eigenschaften, um serialisieren/deserialisieren zu können.

Ich denke an das DataContractSerializer/BinaryFormatter-Verhalten wie Suspendieren des Zustands einer Instanz während der Serialisierung und Fortsetzen während der Deserialisierung. Mit anderen Worten, die Instanzen werden nicht zu einem früheren Zustand "konstruiert", sondern "wiederhergestellt".

Wie bereits erwähnt, ermöglicht das [OnDeserializing] -Attribut, nicht serialisierte Daten synchron zu halten.

+0

Ich würde nicht sagen, dass es "den Zustand einer Instanz auszusetzen", weil ich gerade ein Problem traf, wo mein DataMember INotifyPropertyChanged verwendet und während der Konstruktor nicht aufgerufen wird, wird die NotifyPropertyChanged ausgelöst, so dass das Verhalten nicht ausgesetzt wird. – ForceMagic

Verwandte Themen