SAGA 1: la sérialisation XML (I)
Par amethyste le Aoû 3, 2008 | Dans focus | Réagir »
Il y a à peine 6 mois je n'aurai jamais eu l'idée de faire un article sur la sérialisation XML tellement j'étais convaincu que tout le monde sait ce dont il s'agit.
Et bien non. J'ai rencontré pas mal de gens qui en ignoraient tout, y compris des développeurs expérimentés. En creusant un peu je me suis rendu compte que beaucoup de développeurs ne connaissent pas la différence entre la sérialisation XML et la sérialisation binaire (runtime serialization) et ne comprennent pas clairement l'inutilité de l'attribut SerializableAttribute dans ce contexte.
Et puis je me suis souvenu des nombreuses difficultés rencontré sur des tas de projets pour sérialiser correctement les collections ou certains types de données.
Ajoutons à cela que .NET 2.0 a apporté son lot de nouveautés, j'ai fini par me dire qu'une saga de l'été sur ce sujet pourrait bien être intéressante, avec bien sûr les "notes d'ailleurs" dont j'aime bien conclure mes articles en ces semaines d'été.
Le mieux est de commencer par une présentation de la chose. On attaquera les choses sérieuses la semaine prochaine.
La sérialisation (on rencontre parfois le terme de marshalling), c'est une façon d'encoder une information. Dans notre cas l'information est une instance d'un objet.
La sérialisation XML se réfère un encodage XML. Mais on peut imaginer ce que l'on veut comme SOAP, PDF… Le code source d'une application peut être vu comme une façon de sérialiser des données à la limite.
La question est de déterminer quels sont les contours d'un objet afin de savoir jusqu'où poursuivre l'effort de sérialisation.
Par exemple dit t'on sérialiser un champ private? Si une propriété pointe sur une instance d'un objet faut t'il s'arrêter à une référence vers cet objet ou bien sérialiser l'objet lui-même pour en avoir une copie. Pour son fonctionnement interne, .NET est amené à décorer une instance d'attributs et/ou de membres à usage purement interne au framework. Doit-on également les sérialiser pour avoir une représentation exacte de l'objet? L'objet détient une référence vers une ressource non gérée (un handler par exemple), que doit t'on en faire?
La sérialisation XML répond de façon extrêmement simple à ces questions:
On ne sérialise que les classes qui:
• Ont un constructeur public sans paramètre
• On ne s'intéresse qu'aux propriétés et champs en lecture/écriture
• Seuls les types intrinsèques (int, string…) et quelques types de la BCL (ArrayList…) sont sérialisables par défaut.
• Par défaut on sérialise tous les types qi répondent aux critères précédents.
Il y a quelques autres critères, mais moins importants à connaître.
Le point important à comprendre est que la sérialisation XML est surtout une façon rapide de sauvegarder et/ou transférer des données dans un fichier XML. On ne cherche pas une représentation fidèle de ses états.
Les contraintes imposées par la sérialisation XML sont assez peu nombreuses et la plupart des objets y répondent nativement. C'est cela la sérialisation XML: sérialisation rapide d'un objet quelconque.
Presque tous les objets étant sérialisables au sens XML par défaut, pas besoin de déclarer des attributs quelconques.
Si vous n'êtes intéressé que par la sérialisation XML, inutile donc d'utiliser l'attribut SerializableAttibute.
Ceci étant cet attribut est géré en interne sous la forme d'un drapeau dans l'assemblage. Sa déclaration ne consommant pas de ressources supplémentaire, certains développeurs ont l'habitude de l'ajouter systématiquement.
Pour toute la suite sérialisation signifiera exclusivement sérialisation XML. Si vous souhaitez avoir un aperçu des autres modes, le plus simple est de lire un des articles de la bibliographie [1].
La sérialisation XML dispose de son propre jeu d'attributs. Ils commencent tous par XML. Par exemple XmlIgnoreAttribute permet de soustraire un membre du processus de sérialisation.
On en parle, on en parle. Mais peut être un exemple ne serai pas de refus non?
La classe à sérialiser pourrait ressembler à ceci:
public class Pays { #region Constructeurs /// <summary> /// Constructeur par défaut /// </summary> public Pays() { } #endregion #region Nom [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _Nom; /// <summary> /// Nom du pays /// </summary> public string Nom { [DebuggerStepThrough] get { return _Nom; } [DebuggerStepThrough] set { _Nom = value; } } #endregion public string Capitale; }
Une propriété et un champ.
Le code pour sérialiser est celui-ci:
XmlSerializer serialiseur = new XmlSerializer(typeof(Pays)); using (StreamWriter writer = new StreamWriter(fichier)) { Pays pays=new Pays() {Nom="France", Capitale="Paris"}; serialiseur.Serialize(writer,pays); }
Rien de très compliqué si ce n'est l'utilisation du bloc using parfois oublié, ce qui est la source de bien des bugs.
On recueille le fichier suivant:
<??xml version="1.0" encoding="utf-8"?>
<?Pays xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<?Capitale>Paris<?/Capitale>
<?Nom>France<?/Nom>
<?/Pays>
On peut ultérieurement le relire ainsi:
XmlSerializer serialiseur = new XmlSerializer(typeof(Pays)); using (StreamReader reader = new StreamReader(fichier)) { Pays pays = (Pays)serialiseur.Deserialize(reader); }
Cet exemple servira de fil rouge tout au long de la série.
Un dernier détail pour terminer. Il est en général demandé d'utiliser la convention camel pour le nommage des sections et attributs d'un fichier XML. On pourrait alors transformer les deux membres de la façon suivante:
[XmlElement("nom")] public string Nom { [DebuggerStepThrough] get { return _Nom; } [DebuggerStepThrough] set { _Nom = value; } } [XmlAttribute("capitale")] public string Capitale;
Sans modifier le code on obtient le fichier suivant:
<?xml version="1.0" encoding="utf-8"?>
<?Pays xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" capitale="Paris"><?/strong>
<?strong><?nom>France<?/nom>
<?/Pays>
Voilà pour cette semaine, on parlera entre autres des nouveautés de .NET 2.0 la semaine prochaine.
Notes d'ailleurs
Une anecdote que j'aime bien du mathématicien britannique Hardy qui aurait dit à un astrophysicien célèbre:
Si quelqu'un vous demande si vous êtes astronome et à quoi ça sert l'astronomie, alors la manière correcte de répondre à pareil béotien est la suivante:
- L'astronomie n'est peut être pas utile, et, de fait, mon travail n'est peut être pas important à quelque égards que ce soit, mais j'ai la conviction que mon travail d'astronome est au moins la partie la plus importante de ma personnalité. Le fait que je suis marié, que j'ai un salaire, que je suis brun de peau et que je suis apprécié d'autrui n'a pas de sens hormis pour moi-même. Mais mon travail créatif a de la valeur pour les autres (même si ces autres sont peu nombreux), ce qui a un sens en dehors de moi-même et possède donc pour moi la plus grade valeur qui soit.
Saurez-vous retrouver à l'aide des indices dispersés dans ce texte le nom de l'astrophysicien?
Bibliographie
[1] Article de synthèse sur les différents modèles de sérialisation
http://www.odelmotte.fr/net/framework/serialisation
Aucun commentaire pour le moment
Laisser un commentaire
| « SAGA 2: La sérialisation XML | Faire apparaître intellisense avec une dll » |