Serialization/deserialization complète de classes

Contenu du snippet

Voici une classe permettant de Sérializer/Déserializer (dans un fichier Xml) une classe complètement et automatiquement tant qu'elle soit elle même Sérialisable.
La (dé)sérialization fait une réflexion de votre classe et récupère toutes les valeurs de vos propriété public et seulement public (Field).
La classe doit contenir un constructeur public par défaut (0 argument).
Les membres qui ont besoin d'être instancier, le faire impérativement dans le constructeur.
Tous membres null sera ignoré lors de la sérialization.
La classe peut évolué dans le temps : l'ajout de propriété (sérializable bien sur) est possible sans crée de conflit lors de la déserialization, la propriété sera enregistrer lors de la sérialization.

Source / Exemple :


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Drawing;
using System.IO;

  public class ClassContainerSerializer
    {
        #region Champs de propriétées

        public Point Location { get; set; }
        public string Name { get; set; }
        private string InternalName { get; set; }//Ce membre restera à null lors de la déserialization
        public List<byte> Bytes { get; set; }
        //Cette propriété est privé elle ne sera pas sérializer
        //Et tant mieux car la class System.Drawing.Image n'est pas sérializable
        private Image Image { get; set; }
        //Cette classe qui contient une image est sérializable
        public SerializableImage sImage { get; set; }

        #endregion

        /// <summary>
        /// Constructeur qui crée une instance par défaut de la classe
        /// Ici on mette tous les initialisations obligatoire
        /// </summary>
        public ClassContainerSerializer()
        {
            Bytes = new List<byte>();
            //sImage = new SerializableImage();
        }

        /// <summary>
        /// Initialise l'image de la propriété Image
        /// </summary>
        /// <param name="img">Image de référence</param>
        public void SetImage(Image img)
        {
            Image = img;
        }

        /// <summary>
        /// Récupération de la propriété Image
        /// </summary>
        /// <returns>Image</returns>
        public Image GetImage()
        {
            return Image;
        }

        /// <summary>
        /// Crée une nouvelle instance de la classe avec les données chargé d'un fichier
        /// </summary>
        /// <param name="filename">Chemin de la sauvegarde</param>
        /// <returns>Instance de la nouvelle classe</returns>
        public static ClassContainerSerializer Deserialize(string filename)
        {
            try
            {
                using (XmlReader xR = XmlReader.Create(filename))
                {
                    XmlSerializer xS = new XmlSerializer(typeof(ClassContainerSerializer));
                    return xS.Deserialize(xR) as ClassContainerSerializer;
                }
            }
            catch { return new ClassContainerSerializer(); }
            /*

  • ou return default(ClassContainerSerializer);
  • ou return null;
  • ou throw new MyExceptionForInvalidSerializableOrNotAccessFile();
  • ou ...
  • /
} /// <summary> /// Sauvegarde dans un fichier votre classe /// </summary> /// <param name="filename">Chemin de sauvegarde</param> /// <param name="ccs">Instance de la classe</param> /// <returns>Validité de l'opération</returns> public static bool Serialize(string filename, ClassContainerSerializer ccs) { try { using (XmlWriter xW = XmlWriter.Create(filename)) { //ccs peut être type différent alors pour évité des conflits nous prendrons le type de base XmlSerializer xS = new XmlSerializer(typeof(ClassContainerSerializer)); xS.Serialize(xW, ccs); } } catch { return false; } return true; } } /// <summary> /// Attention certain membre sont a refaire /// Etant donnée que cette classe n'est pas l'objet de l'intitulé /// Je me suis permis de ne pas la remanier /// Par conscéquant j'ai mis le préfixe [Obsolete] pour tous membres ou il y aurai un doute /// </summary> public class SerializableImage { private Image _image; private bool _modified; public int[] ImageData { get; set; } public string Name { get; set; } public Image Image { get { if (ImageData.Length == 0) return null; if (_modified || _image == null) { MemoryStream ms = new MemoryStream(); foreach (int v in ImageData) ms.WriteByte(Convert.ToByte(v)); _image = Image.FromStream(ms); _modified = false; } return _image; } } public Size Size { get { return Image.Size; } } public SerializableImage() { ImageData = new int[0]; Name = "SerializableImage"; } public SerializableImage(string filename) : this() { Open(filename); Name = Global.GetFileName(filename); } public SerializableImage(Stream stream) : this() { Open(stream); } public SerializableImage(Image image) : this() { string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Guid.NewGuid().ToString() + "."); string s = image.RawFormat.ToString(); if (image.RawFormat.Equals(ImageFormat.Bmp)) filename += "bmp"; else if (image.RawFormat.Equals(ImageFormat.Emf)) filename += "emf"; else if (image.RawFormat.Equals(ImageFormat.Exif)) filename += "exif"; else if (image.RawFormat.Equals(ImageFormat.Gif)) filename += "gif"; else if (image.RawFormat.Equals(ImageFormat.Icon)) filename += "icon"; else if (image.RawFormat.Equals(ImageFormat.Jpeg)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.MemoryBmp)) filename += "bmp"; else if (image.RawFormat.Equals(ImageFormat.Png)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.Tiff)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.Wmf)) filename += "jpeg"; else filename += "jpeg"; image.Save(filename); Open(filename); File.Delete(filename); } [Obsolete] private static MemoryStream GetStream(Image image) { string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Guid.NewGuid().ToString() + "."); string s = image.RawFormat.ToString(); if (image.RawFormat.Equals(ImageFormat.Bmp)) filename += "bmp"; else if (image.RawFormat.Equals(ImageFormat.Emf)) filename += "emf"; else if (image.RawFormat.Equals(ImageFormat.Exif)) filename += "exif"; else if (image.RawFormat.Equals(ImageFormat.Gif)) filename += "gif"; else if (image.RawFormat.Equals(ImageFormat.Icon)) filename += "icon"; else if (image.RawFormat.Equals(ImageFormat.Jpeg)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.MemoryBmp)) filename += "bmp"; else if (image.RawFormat.Equals(ImageFormat.Png)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.Tiff)) filename += "jpeg"; else if (image.RawFormat.Equals(ImageFormat.Wmf)) filename += "jpeg"; else filename += "jpeg"; image.Save(filename); MemoryStream ms = new MemoryStream(); using (StreamReader sr = new StreamReader(filename)) { while (sr.BaseStream.Position < sr.BaseStream.Length) { ms.WriteByte(Convert.ToByte(sr.BaseStream.ReadByte())); } } File.Delete(filename); return ms; } private Stream GetStream() { MemoryStream ms = new MemoryStream(); foreach (int v in ImageData) ms.WriteByte(Convert.ToByte(v)); return ms; } public void Open(string filename) { using (StreamReader sr = new StreamReader(filename)) { Open(sr.BaseStream); } } public void Open(Stream stream) { List<int> id = new List<int>(); while (stream.Position < stream.Length) { id.Add(stream.ReadByte()); } ImageData = id.ToArray(); _modified = true; } public static implicit operator Image(SerializableImage image) { return image.Image; } public static implicit operator SerializableImage(Image image) { return new SerializableImage(image); } public static implicit operator Stream(SerializableImage image) { MemoryStream ms = new MemoryStream(); foreach (int v in image.ImageData) ms.WriteByte(Convert.ToByte(v)); return ms; } /// <summary> /// Outils pour Xna à ignoré /// </summary> /// <param name="graphicsDevice"></param> /// <returns></returns> [Obsolete] public Texture2D ToTexture(GraphicsDevice graphicsDevice) { if (Image == null) return null; return Texture2D.FromFile(graphicsDevice, GetStream()); } }

Conclusion :


Préparez bien vos classes faites très attention à la possibilité de sérialisation de vos classe et si besoin est incrémenté l'interface ISerializable. Je ne sait pas l'utilisé encore mais pour une classe comme System.Drawing.Image qui n'est pas sérializable j'ai été obligé de recrée une classe qui est sérializable comprenant les informations de l'image. le préfixe [Serializabe] ne permet pas à une classe de sérializer tous ses membres si l'un d'eux n'est pas sérializable une exception sera levé lors de la réflexion de votre classe.

A voir également