web-dev-qa-db-fra.com

Sérialisation des données des membres privés

J'essaie de sérialiser un objet en XML comportant un certain nombre de propriétés, dont certaines sont en lecture seule.

public Guid Id { get; private set; }

J'ai marqué la classe [Serializable] et j'ai implémenté l'interface ISerializable.

Vous trouverez ci-dessous le code que j'utilise pour sérialiser mon objet.

public void SaveMyObject(MyObject obj)
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
    TextWriter tw = new StreamWriter(_location);
    serializer.Serialize(tw, obj);
    tw.Close();
}

Malheureusement, ce message tombe sur la première ligne.

InvalidOperationException n'a pas été gérée: Impossible de générer une classe temporaire (résultat = 1) . erreur CS0200: Impossible d'affecter une propriété ou un indexeur 'MyObject.Id' - lecture seule

Si je mets la propriété Id au public, cela fonctionne bien. Quelqu'un peut-il me dire si je fais quelque chose, ou au moins si c'est même possible?

73
Jon Mitchell

Vous pouvez utiliser DataContractSerializer (mais notez que vous ne pouvez pas utiliser d'attributs xml - uniquement des éléments xml):

using System;
using System.Runtime.Serialization;
using System.Xml;
[DataContract]
class MyObject {
    public MyObject(Guid id) { this.id = id; }
    [DataMember(Name="Id")]
    private Guid id;
    public Guid Id { get {return id;}}
}
static class Program {
    static void Main() {
        var ser = new DataContractSerializer(typeof(MyObject));
        var obj = new MyObject(Guid.NewGuid());
        using(XmlWriter xw = XmlWriter.Create(Console.Out)) {
            ser.WriteObject(xw, obj);
        }
    }
}

Alternativement, vous pouvez implémenter IXmlSerializable et tout faire vous-même - mais cela fonctionne avec XmlSerializer, au moins.

60
Marc Gravell

Vous pouvez utiliser le System.Runtime.Serialization.NetDataContractSerializer. Il est plus puissant et corrige quelques problèmes du sérialiseur Xml classique.

Notez qu'il existe différents attributs pour celui-ci.

[DataContract]
public class X
{
  [DataMember]
  public Guid Id { get; private set; }
}


NetDataContractSerializer serializer = new NetDataContractSerializer();
TextWriter tw = new StreamWriter(_location);
serializer.Serialize(tw, obj);

Modifier:

Mise à jour basée sur le commentaire de Marc: Vous devriez probablement utiliser System.Runtime.Serialization.DataContractSerializer dans votre cas pour obtenir un XML propre. Le reste du code est le même.

6
Stefan Steinegger

Les champs en lecture seule ne seront pas sérialisés à l'aide de la variable XmlSerializer; cela est dû à la nature du mot clé readonly

De MSDN:

Le mot clé readonly est un modificateur que vous pouvez utiliser sur les champs. Lorsqu'une déclaration de champ inclut un modificateur readonly, les assignations aux champs introduits par la déclaration ne peuvent s'effectuer que dans le cadre de la déclaration ou dans un constructeur de la même classe.

Donc ... vous auriez besoin de définir la valeur des champs dans le constructeur par défaut ... 

2
flalar

Ce n'est pas possible avec ce mode de sérialisation particulier (voir les autres commentaires pour des solutions de contournement). Si vous voulez vraiment laisser votre mode de sérialisation tel quel, vous devez contourner les limites de la structure de celui-ci. Voir cet exemple

Esentiellement, cochez la propriété public, mais émettez une exception si vous y accédez à un moment autre que la désérialisation.

0
jvenema