2009-07-02 11 views
84

Mi sono appena reso conto di qualcosa di pazzesco, che presumo assolutamente impossibile: quando deserializzi un oggetto, il DataContractSerializer non chiama il costruttore!DataContractSerializer non chiama il mio costruttore?

Prendete questa classe, per esempio:

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

Quando ho deserializzare un oggetto di quella classe, il punto di interruzione non viene colpito. Non ho assolutamente idea di come sia possibile, dal momento che è l'unico costruttore di questo oggetto!

ho pensato che forse un costruttore aggiuntivo è stato generato dal compilatore a causa dell'attributo DataContract, ma non riuscivo a trovare attraverso la riflessione ...

Quindi, quello che vorrei sapere è questo: come si può creare un'istanza della mia classe senza che venga chiamato il costruttore ??

NOTA: so che posso utilizzare l'attributo OnDeserializing per inizializzare il mio oggetto quando inizia la deserializzazione, questo non è l'argomento della mia domanda.

+3

o "OnDeserialized", quando l'oggetto è deserializzato, per compilare i campi mancanti. –

+1

Anche questa domanda mi è passata per la testa: http://stackoverflow.com/questions/178645/how-does-wcf-deserialization-ststantiate-objects-withoutcalling-a-constructor –

risposta

118

DataContractSerializer (come BinaryFormatter) non utilizza alcun costruttore. Crea l'oggetto come memoria vuota.

Ad esempio:

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

L'ipotesi è che il processo di deserializzazione (o callback se necessario) verrà inizializzato pienamente.

+82

This is CHEATING !! – Cheeso

+0

Il costruttore non deve essere chiamato affatto durante la deserializzazione. Se è stato chiamato, quindi 1) E le risorse che hai creato nel costruttore? Perderanno! 2) Stai inizializzando l'oggetto due volte, una volta nel costruttore e una volta i valori deserializzati. – Dudu

+1

@Dodu a: ciò non causerà una perdita b: che (chiamando il ctor) è come funzionano molti serializzatori; in entrambi i casi è generalmente valido come registro, in quanto il comportamento è compreso e designer in conformità –

3

Ci sono alcuni scenari che non sarebbero possibili senza questo comportamento. Pensa a quanto segue:

1) Si dispone di un oggetto con un costruttore che imposta la nuova istanza su uno stato "inizializzato". Quindi alcuni metodi vengono chiamati su quell'istanza, che lo portano in uno stato "elaborato". Non si desidera creare nuovi oggetti con lo stato "elaborato", ma si desidera comunque de serializzare/deserializzare l'istanza.

2) È stata creata una classe con un costruttore privato e alcune proprietà statiche per controllare un piccolo insieme di parametri consentiti del costruttore. Ora puoi ancora serializzarli/deserializzarli.

XmlSerializer ha il comportamento previsto. Ho avuto alcuni problemi con XmlSerializer perché ha bisogno di un costruttore predefinito. In relazione a ciò, a volte ha senso avere setter di proprietà privata. Ma XmlSerializer necessita anche di getter pubblico e setter sulle proprietà per serializzare/deserializzare.

Penso al comportamento DataContractSerializer/BinaryFormatter come sospendere lo stato di un'istanza durante la serializzazione e riprendere durante la deserializzazione. In altre parole, le istanze non sono "costruite" ma "ripristinate" in uno stato precedente.

Come già accennato, l'attributo [OnDeserializing] consente di mantenere i dati non serializzati in sincronizzazione.

+0

Non direi che "sospende lo stato di un'istanza" perché ho appena riscontrato un problema in cui DataMember stava usando INotifyPropertyChanged e mentre il costruttore non viene chiamato, attiverà NotifyPropertyChanged in modo che il comportamento non venga sospeso. – ForceMagic