web-dev-qa-db-fra.com

Pourquoi la classe XML-Serializable a besoin d'un constructeur sans paramètre

J'écris du code pour faire la sérialisation XML. Avec la fonction ci-dessous.

public static string SerializeToXml(object obj)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);
        return writer.ToString();
    }
}

Si l'argument est une instance de classe sans constructeur sans paramètre, il lève une exception.

Exception non gérée: System.InvalidOperationException: CSharpConsole.Foo ne peut pas être sérialisé car il ne possède pas de constructeur sans paramètre. à System.Xml.Serialization.TypeDesc.CheckSupported () à System.Xml.Serialization.TypeScope.GetTypeDesc (Type, source MemberInfo, Référence directe booléenne, LancerOnErreur booléen) à System.Xml.Serialization.ModelScope.GetTypeModel (en anglais) Référence directe booléenne) à System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (Type, racine XmlRootAttribute, String defaultNamespace) à System.Xml.Serialization.XmlSerializer..ctor (Type Type, String defaultName) à System.Xml.Serialization. XmlSerializer..ctor (Type type)

Pourquoi faut-il un constructeur sans paramètre pour permettre la sérialisation xml?

EDIT: merci pour la réponse de cfeduke. Le constructeur sans paramètre peut être privé ou interne.

167
Morgan Cheng

Lors de la désérialisation d'un objet, la classe responsable de la désérialisation d'un objet crée une instance de la classe sérialisée, puis remplit les champs et les propriétés sérialisés uniquement après l'acquisition d'une instance à peupler.

Vous pouvez créer votre constructeur private ou internal si vous le souhaitez, à condition que ce soit sans paramètre.

234
cfeduke

C'est une limitation de XmlSerializer. Notez que BinaryFormatter et DataContractSerializer ne le nécessitent pas - ils peuvent créer un objet non initialisé dans l’éther et s’initialiser. pendant la désérialisation.

Puisque vous utilisez xml, vous pouvez utiliser DataContractSerializer et marquer votre classe avec [DataContract]/[DataMember], Mais notez que cela modifie le schéma (par exemple, il n'y a pas équivalent de [XmlAttribute] - tout devient élément).

Mise à jour: si vous voulez vraiment savoir, BinaryFormatter et autres utilisez FormatterServices.GetUninitializedObject() pour créer l'objet sans appeler le constructeur. Probablement dangereux; Je ne recommande pas de l'utiliser trop souvent ;-p Voir aussi les remarques sur MSDN:

Comme la nouvelle instance de l'objet est initialisée à zéro et qu'aucun constructeur n'est exécuté, il est possible que l'objet ne représente pas un état considéré comme valide par cet objet. La méthode actuelle ne doit être utilisée pour la désérialisation que lorsque l'utilisateur a l'intention de renseigner immédiatement tous les champs. Il ne crée pas de chaîne non initialisée, car la création d'une instance vide d'un type immuable ne sert à rien.

J'ai mon moteur de sérialisation propre , mais je n'ai pas l'intention de le faire utiliser FormatterServices; J'aime bien savoir qu'un constructeur ( un constructeur ) a effectivement été exécuté.

73
Marc Gravell

Tout d’abord, c’est ce qui est écrit dans documentation . Je pense que c’est l’un de vos champs de classe, pas le principal - et comment voulez-vous que déserialiser le reconstruise sans construction sans paramètres?

Je pense qu'il existe une solution pour rendre le constructeur privé.

0
Dmitry Khalatov