Programmation C sharp/La sérialisation
La sérialisation est un procédé d'entrée-sortie permettant de sauvegarder et recharger l'état d'un objet. Cette fonctionnalité permet de faire abstraction du format de fichier utilisé. Celui-ci dépend de l'outil de sérialisation utilisé.
L'état d'un objet correspond à l'ensemble des valeurs de ses champs. Les propriétés sont calculées en fonction des champs, et le code des méthodes ne change pas au cours de l'exécution.
Attributs
modifierL'attribut System.SerializableAttribute
marque les classes dont les instances peuvent être sérialisées. Si l'attribut est absent pour une classe, la sérialisation de ses instances provoquera une exception.
Exemple :
[Serializable]
class Facture
{
public string Client;
public double TotalHT;
public double TotalTTC;
}
L'attribut System.NonSerializedAttribute
marque les champs qu'il ne faut pas enregistrer. C'est le cas des champs dont on peut retrouver la valeur par calcul, par exemple.
Exemple :
[Serializable]
class Facture
{
public string Client;
public double TotalHT;
[NonSerialized]
public double TotalTTC; // = TotalHT * (1 + taux_TVA/100)
}
Quand la classe évolue, de nouveaux champs sont ajoutés à la classe, d'autres sont retirés.
L'attribut System.Runtime.Serialization.OptionalFieldAttribute
marque les champs optionnels lors de la désérialisation (lecture de l'objet). Il est donc possible de marquer les nouveaux champs comme optionnels, et garder les anciens champs (marqués optionnels également) pour garder la compatibilité avec les anciens fichiers.
Exemple :
[Serializable]
class Facture
{
public string Client;
public double TotalHT;
[NonSerialized]
public double TotalTTC;
[OptionalField]
public string AdresseLivraison; // Nouveau champ
}
Dans cet exemple, la classe Facture permettra de lire des fichiers d'objets Facture
contenant le champ AdresseLivraison
ou non.
La sérialisation
modifierLe format de sérialisation dépend de la classe utilisée pour sérialiser les objets.
La classe System.Runtime.Serialization.Formatter
modifier
Cette classe abstraite définit les méthodes suivantes :
void Serialize( System.IO.Stream serializationStream, object graph);
- Cette méthode enregistre l'objet
graph
dans le flux d'entrée-sortie spécifié.
object Deserialize( System.IO.Stream serializationStream);
- Cette méthode retourne l'objet lu depuis le flux d'entrée-sortie spécifié.
Les classes dérivées définissent un format concret de sérialisation :
- La classe System.Runtime.Serialization.Formatters.Binary.BinaryFormatter permet de sérialiser dans un format binaire,
- La classe System.Runtime.Serialization.Formatters.Soap.SoapFormatter permet de sérialiser au format SOAP.
Une classe dérivée de System.Runtime.Serialization.Formatter
sérialise les attributs et les évènements d'un objet, quel que soit l'accès associé (public, protégé, privé, ou par défaut).
Format XML
modifierLa classe System.Xml.Serialization.XmlSerializer
permet de sérialiser au format XML. Elle ne dérive pas de la classe System.Runtime.Serialization.Formatter
, et possède les méthodes suivantes :
void Serialize( System.IO.Stream stream, object o); void Serialize( System.IO.TextWriter textWriter, object o); void Serialize( System.Xml.XmlWriter xmlWriter, object o);
- Ces méthodes enregistrent l'objet
o
dans le flux d'entrée-sortie spécifié.
object Deserialize( System.IO.Stream stream); object Deserialize( System.IO.TextReader textReader); object Deserialize( System.Xml.XmlReader xmlReader);
- Ces méthodes retournent l'objet lu depuis le flux d'entrée-sortie spécifié.
Pour le format XML, les attributs Serializable
et NonSerialized
sont ignorés :
- Toute classe est sérialisable en XML,
- L'attribut
System.Xml.Serialization.XmlIgnoreAttribute
marque les champs à ignorer lors de la sérialisation.
La classe System.Xml.Serialization.XmlSerializer
sérialise les attributs et les propriétés en lecture/écriture publics d'un objet, si la valeur n'est pas nulle. Donc la sérialisation en XML ignore :
- les attributs et propriétés retournant une valeur nulle,
- les attributs et propriétés protégés ou privés,
- les propriétés en lecture seule (impossible de les désérialiser),
- les propriétés en écriture seule (impossible de les sérialiser).
Pour en savoir plus :
- (anglais) XML Serialization in the .NET Framework
Sérialisation personnalisée
modifierIl est possible de personnaliser la manière de sérialiser un objet en implémentant l'interface System.Runtime.Serialization.ISerializable
.
Cette interface n'a qu'une méthode, invoquée lors de la sérialisation :
void GetObjectData (
SerializationInfo info,
StreamingContext context )
Mais la classe doit également comporter le constructeur suivant, invoqué lors de la désérialisation :
protected NomDeClasse(SerializationInfo info, StreamingContext context)
L'objet de type SerializationInfo permet la sérialisation et la désérialisation de l'objet. Chaque valeur sauvegardée est associé à un nom unique. Cet objet possède les méthodes suivantes :
public void AddValue(string name, T value) // tout type de valeur public object GetValue(string name, Type type) public T GetType(string name) // GetByte, GetChar, GetInt16, GetDecimal, GetDateTime, ...
L'implémentation de la méthode GetObjectData
fait appel à la méthode AddValue
de l'objet info
pour ajouter une valeur à sauvegarder. Le constructeur utilise la méthode GetValue
ou les méthodes GetType
pour retrouver la valeur sauvegardée.
Exemple :
[Serializable]
public class Personne : ISerializable
{
private string nom;
private int age;
public Personne() { }
protected Personne(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new System.ArgumentNullException("info");
nom = (string)info.GetValue("Nom", typeof(string));
age = (int)info.GetValue("Age", typeof(int));
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new System.ArgumentNullException("info");
info.AddValue("Nom", nom);
info.AddValue("Age", age);
}
}