web-dev-qa-db-fra.com

DataContractSerializer n'appelle pas mon constructeur?

Je viens de réaliser quelque chose de fou, que j'ai supposé complètement impossible: lors de la désérialisation d'un objet, le DataContractSerializer n'appelle pas le constructeur!

Prenez ce cours, par exemple:

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

Lorsque je désérialise un objet de cette classe, le point d'arrêt n'est pas atteint. Je ne sais absolument pas comment c'est possible, car c'est le seul constructeur pour cet objet!

J'ai supposé que peut-être un constructeur supplémentaire avait été généré par le compilateur à cause de l'attribut DataContract, mais je ne l'ai pas trouvé par réflexion ...

Donc, ce que je voudrais savoir, c'est ceci: comment une instance de ma classe pourrait-elle être créée sans que le constructeur soit appelé ??

REMARQUE: je sais que je peux utiliser l'attribut OnDeserializing pour initialiser mon objet lorsque la désérialisation commence, ce n'est pas le sujet de ma question.

96
Thomas Levesque

DataContractSerializer (comme BinaryFormatter) n'utilise pas le constructeur any. Il crée l'objet comme mémoire vide.

Par exemple:

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

L'hypothèse est que le processus de désérialisation (ou les rappels si nécessaire) l'initialise complètement.

132
Marc Gravell

Il existe certains scénarios qui ne seraient pas possibles sans ce comportement. Pensez à ce qui suit:

1) Vous avez un objet qui a un constructeur qui définit la nouvelle instance sur un état "initialisé". Ensuite, certaines méthodes sont appelées sur cette instance, ce qui la met dans un état "traité". Vous ne voulez pas créer de nouveaux objets ayant l'état "traité", mais vous voulez toujours désérialiser/désérialiser l'instance.

2) Vous avez créé une classe avec un constructeur privé et quelques propriétés statiques pour contrôler un petit ensemble de paramètres de constructeur autorisés. Maintenant, vous pouvez toujours les sérialiser/désérialiser.

XmlSerializer a le comportement que vous attendiez. J'ai eu quelques problèmes avec le XmlSerializer car il a besoin d'un constructeur par défaut. À cet égard, il est parfois logique d'avoir des propriétaires de biens privés. Mais XmlSerializer a également besoin d'un getter et d'un setter publics sur les propriétés afin de sérialiser/désérialiser.

Je pense au comportement DataContractSerializer/BinaryFormatter comme la suspension de l'état d'une instance pendant la sérialisation et la reprise pendant la désérialisation. En d'autres termes, les instances ne sont pas "construites" mais "restaurées" à un état antérieur.

Comme vous l'avez déjà mentionné, l'attribut [OnDeserializing] permet de synchroniser les données non sérialisées.

3
BasvdL