.NET - Sérialisation XML et dictionnaire
Une astuce proposée par François DORIN

Le , par François DORIN, Responsable .NET & Magazine
Bonjour à tous,

Petit billet rapide avant de partir en congés.

Je ne sais pas pour vous, mais il m'arrive fréquemment d'avoir une structure ou une classe, que je sérialise en XML ou en JSON. Et même souvent, dans le cas d'applications Web, je passe même de l'un à l'autre.

Une des difficultés que l'on peut rencontrer, c'est que la sérialisation XML s’accommode mal avec les données présentes dans un dictionnaire clé/valeur, où la clé est une chaîne de caractères. Chose pourtant très aisée dans d'autres formats comme le JSON.

Ce n'est pas impossible, bien entendu, mais cela nécessite une intervention. La plus classique, et sans doute la plus naturelle, est de gérer manuellement la sérialisation. Même si cette approche est tout à fait fonctionnelle, cela nécessite une intervention manuelle à chaque sérialisation/désérialisation, et requiert de mettre en place des méthodes qui devront obligatoirement être appelées.

La solution que je vous propose aujourd'hui est un peu différente. Il s'agit de modifier la classe à sérialiser, pour qu'elle gère elle-même la sérialisation.

Code C# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 [XmlRoot("Personne")] 
    public class Personne 
    { 
        public string Nom {get; set;} 
        public string Prenom {get; set;} 
        public string DateNaissance {get; set;} 
  
        [XmlIgnore] 
        public Dictionary<string, string> Adresses{ get; set; } 
  
        [XmlArray("Adresses")] 
        [XmlArrayItem("Adresse")] 
        public KeyValueXml<string, string>[] AdressesXMLProxy 
        { 
            get 
            { 
                return this.Adresses.Select( x => new KeyValueXml<string, string>(x.Key, x.Value)).ToArray() ; 
            } 
            set 
            { 
                if (value != null) 
                { 
                    this.Adresses = new Dictionary<string, string>(); 
                    foreach (var pair in value) 
                    { 
                        this.Adresses[pair.Key] = pair.Value; 
                    } 
                } 
                else 
                { 
                    this.Adresses = null; 
                } 
            } 
        }         
  
        [Serializable] 
        public struct KeyValueXml<TKey, TValue> 
        { 
            public KeyValueXml(TKey key, TValue value) 
            { 
                this.Key = key; 
                this.Value = value; 
            } 
  
            public TKey Key { get; set; } 
            public TValue Value { get; set; } 
        } 
    }

Ici, la propriété qui nous intéresse est la propriété Adresses.

Comme nous pouvons le remarquer, c'est une propriété du type Dictionary. Malheureusement, ce type n'est pas sérialisable. Aussi, l'astuce consiste ici à le marquer comme non sérialisable via l'attribut [XmlIgnore]. Il ne reste alors qu'à définir une autre autre propriété, qui sera calculée à partir de la propriété Adresses, et nous nous arrangerons pour que celle-ci soit sérialisable.

En C#, un dictionnaire peut être vu comme un tableau de tuple clé/valeur. Un tableau est sérialisable. Il reste donc à s'assurer que le type utilisé pour représenter le tuple soit aussi sérialisable. Ici, il s'agit du type KeyValueXml. Un connaisseur aurait pu suggérer d'utiliser directement la structure KeyValuePair définie par le framework .NET. Malheureusement, ce n'est pas possible, car ce type étant immutable, il n'est pas désérialisable.

L'idée consiste donc à définir une propriété "proxy" dont le type sera un tableau de KeyValueXml. Cette propriété porte ici le nom de AdressesXMLProxy. Comme elle agit comme un proxy, elle ne stocke rien par elle-même. Elle est liée, aussi bien dans son getter que son setter à la propriété Adresses.

Combiné avec des attributs comme XmlArray, XmlArrayItem ou encore XmlAttribute, on peut alors définir de manière assez fine le résultat souhaité.

En espérant que cette astuce puisse vous servir un jour...


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster un commentaire

Avatar de tomlev tomlev - Rédacteur/Modérateur https://www.developpez.com
le 10/07/2018 à 12:32
J'avais parlé d'une approche similaire il y a quelques années
https://tlevesque.developpez.com/dot...ization-2/#LII
Contacter le responsable de la rubrique Accueil