web-dev-qa-db-fra.com

Sérialiser un objet en chaîne

J'ai la méthode suivante pour enregistrer un objet dans un fichier:

// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
    TextWriter textWriter = new StreamWriter(filename);

    xmlSerializer.Serialize(textWriter, toSerialize);
    textWriter.Close();
}

J'avoue que je ne l'ai pas écrit (je l'ai seulement converti en une méthode d'extension prenant un paramètre de type).

Maintenant, j'en ai besoin pour me redonner le code XML sous forme de chaîne (plutôt que de l'enregistrer dans un fichier). Je suis à la recherche, mais je ne l'ai pas encore compris.

Je pensais que cela pourrait être très facile pour quelqu'un de familier avec ces objets. Sinon, je le saurai éventuellement.

264
Vaccano

Utilisez un StringWriter au lieu de StreamWriter :

public static string SerializeObject<T>(this T toSerialize)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

    using(StringWriter textWriter = new StringWriter())
    {
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }
}

Notez qu'il est important d'utiliser toSerialize.GetType() au lieu de typeof(T) dans le constructeur XmlSerializer: si vous utilisez la première, le code couvre toutes les sous-classes possibles de T (valables pour la méthode), mais l'utilisation du dernier échouera lors de la transmission d'un type dérivé. de T. Voici un lien avec un exemple de code qui motive cette instruction, avec XmlSerializer lançant un Exception lorsque typeof(T) est utilisé, car vous transmettez une instance d'un type dérivé à une méthode qui appelle SerializeObject définie dans la classe de base du type dérivé : http://ideone.com/1Z5J1 .

En outre, Ideone utilise Mono pour exécuter du code. La Exception réelle que vous obtiendrez en utilisant le runtime Microsoft .NET a une Message différente de celle affichée sur Ideone, mais elle échoue de la même manière.

463
dtb

Je sais que ce n'est pas vraiment une réponse à la question, mais en fonction du nombre de votes pour la question et de la réponse acceptée, je suppose que les gens utilisent le code pour sérialiser un objet en chaîne.

L'utilisation de la sérialisation XML ajoute des déchets de texte inutiles à la sortie.

Pour la classe suivante

public class UserData
{
    public int UserId { get; set; }
}

il génère 

<?xml version="1.0" encoding="utf-16"?>
<UserData xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <UserId>0</UserId>
</UserData>

Une meilleure solution consiste à utiliser la sérialisation JSON (l’un des meilleurs est Json.NET ) . Pour sérialiser un objet:

var userData = new UserData {UserId = 0};
var userDataString = JsonConvert.SerializeObject(userData);

Pour désérialiser un objet:

var userData = JsonConvert.DeserializeObject<UserData>(userDataString);

La chaîne JSON sérialisée ressemblerait à ceci:

{"UserId":0}
66
xhafan

Sérialiser et désérialiser:

    public static T Deserialize<T>(this string toDeserialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        using(StringReader textReader = new StringReader(toDeserialize))
        {      
            return (T)xmlSerializer.Deserialize(textReader);
        }
    }

    public static string Serialize<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        using(StringWriter textWriter = new StringWriter())
        {
            xmlSerializer.Serialize(textWriter, toSerialize);
            return textWriter.ToString();
        }
    }
49
ADM-IT

Note de sécurité du code

En ce qui concerne la réponse acceptée , il est important d'utiliser toSerialize.GetType() au lieu de typeof(T) dans le constructeur XmlSerializer: si vous utilisez le premier, le code couvre tous les scénarios possibles, mais l'utilisation du dernier échoue parfois. 

Voici un lien avec un exemple de code motivant cette instruction, avec XmlSerializer levant une exception lorsque typeof(T) est utilisé, car vous transmettez une instance d'un type dérivé à une méthode qui appelle SerializeObject<T>() et qui est définie dans la classe de base du type dérivé: http://ideone.com/1Z5J1 . Notez que Ideone utilise Mono pour exécuter le code: l’exception que vous obtiendriez en utilisant le runtime Microsoft .NET a un message différent de celui affiché sur Ideone, mais il échoue de la même manière. 

Par souci d'exhaustivité, je poste ici l'exemple de code complet pour référence ultérieure, au cas où Ideone (où j'ai posté le code) ne serait plus disponible:

using System;
using System.Xml.Serialization;
using System.IO;

public class Test
{
    public static void Main()
    {
        Sub subInstance = new Sub();
        Console.WriteLine(subInstance.TestMethod());
    }

    public class Super
    {
        public string TestMethod() {
            return this.SerializeObject();
        }
    }

    public class Sub : Super
    {
    }
}

public static class TestExt {
    public static string SerializeObject<T>(this T toSerialize)
    {
        Console.WriteLine(typeof(T).Name);             // PRINTS: "Super", the base/superclass -- Expected output is "Sub" instead
        Console.WriteLine(toSerialize.GetType().Name); // PRINTS: "Sub", the derived/subclass

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        StringWriter textWriter = new StringWriter();

        // And now...this will throw and Exception!
        // Changing new XmlSerializer(typeof(T)) to new XmlSerializer(subInstance.GetType()); 
        // solves the problem
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }
}
37
Fulvio

Mon 2p ...

        string Serialise<T>(T serialisableObject)
        {
            var xmlSerializer = new XmlSerializer(serialisableObject.GetType());

            using (var ms = new MemoryStream())
            {
                using (var xw = XmlWriter.Create(ms, 
                    new XmlWriterSettings()
                        {
                            Encoding = new UTF8Encoding(false),
                            Indent = true,
                            NewLineOnAttributes = true,
                        }))
                {
                    xmlSerializer.Serialize(xw,serialisableObject);
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }
10
oPless
public static string SerializeObject<T>(T objectToSerialize)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream memStr = new MemoryStream();

            try
            {
                bf.Serialize(memStr, objectToSerialize);
                memStr.Position = 0;

                return Convert.ToBase64String(memStr.ToArray());
            }
            finally
            {
                memStr.Close();
            }
        }

        public static T DerializeObject<T>(string objectToDerialize)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            byte[] byteArray = Convert.FromBase64String(objectToDerialize);
            MemoryStream memStr = new MemoryStream(byteArray);

            try
            {
                return (T)bf.Deserialize(memStr);
            }
            finally
            {
                memStr.Close();
            }
        }
4
teapeng

Je n'ai pas pu utiliser la méthode JSONConvert proposée par xhafan

Dans .Net 4.5, même après avoir ajouté la référence d'assembly "System.Web.Extensions", je ne pouvais toujours pas accéder à JSONConvert.

Cependant, une fois que vous avez ajouté la référence, vous pouvez obtenir la même chaîne imprimée en utilisant:

JavaScriptSerializer js = new JavaScriptSerializer();
string jsonstring = js.Serialize(yourClassObject);
1
Thomas Tiveron

Je me sentais comme si j'avais besoin de partager ce code manipulé avec la réponse acceptée - comme je n'ai aucune réputation, je suis incapable de commenter ...

using System;
using System.Xml.Serialization;
using System.IO;

namespace ObjectSerialization
{
    public static class ObjectSerialization
    {
        // THIS: (C): https://stackoverflow.com/questions/2434534/serialize-an-object-to-string
        /// <summary>
        /// A helper to serialize an object to a string containing XML data of the object.
        /// </summary>
        /// <typeparam name="T">An object to serialize to a XML data string.</typeparam>
        /// <param name="toSerialize">A helper method for any type of object to be serialized to a XML data string.</param>
        /// <returns>A string containing XML data of the object.</returns>
        public static string SerializeObject<T>(this T toSerialize)
        {
            // create an instance of a XmlSerializer class with the typeof(T)..
            XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

            // using is necessary with classes which implement the IDisposable interface..
            using (StringWriter stringWriter = new StringWriter())
            {
                // serialize a class to a StringWriter class instance..
                xmlSerializer.Serialize(stringWriter, toSerialize); // a base class of the StringWriter instance is TextWriter..
                return stringWriter.ToString(); // return the value..
            }
        }

        // THIS: (C): VPKSoft, 2018, https://www.vpksoft.net
        /// <summary>
        /// Deserializes an object which is saved to an XML data string. If the object has no instance a new object will be constructed if possible.
        /// <note type="note">An exception will occur if a null reference is called an no valid constructor of the class is available.</note>
        /// </summary>
        /// <typeparam name="T">An object to deserialize from a XML data string.</typeparam>
        /// <param name="toDeserialize">An object of which XML data to deserialize. If the object is null a a default constructor is called.</param>
        /// <param name="xmlData">A string containing a serialized XML data do deserialize.</param>
        /// <returns>An object which is deserialized from the XML data string.</returns>
        public static T DeserializeObject<T>(this T toDeserialize, string xmlData)
        {
            // if a null instance of an object called this try to create a "default" instance for it with typeof(T),
            // this will throw an exception no useful constructor is found..
            object voidInstance = toDeserialize == null ? Activator.CreateInstance(typeof(T)) : toDeserialize;

            // create an instance of a XmlSerializer class with the typeof(T)..
            XmlSerializer xmlSerializer = new XmlSerializer(voidInstance.GetType());

            // construct a StringReader class instance of the given xmlData parameter to be deserialized by the XmlSerializer class instance..
            using (StringReader stringReader = new StringReader(xmlData))
            {
                // return the "new" object deserialized via the XmlSerializer class instance..
                return (T)xmlSerializer.Deserialize(stringReader);
            }
        }

        // THIS: (C): VPKSoft, 2018, https://www.vpksoft.net
        /// <summary>
        /// Deserializes an object which is saved to an XML data string.
        /// </summary>
        /// <param name="toDeserialize">A type of an object of which XML data to deserialize.</param>
        /// <param name="xmlData">A string containing a serialized XML data do deserialize.</param>
        /// <returns>An object which is deserialized from the XML data string.</returns>
        public static object DeserializeObject(Type toDeserialize, string xmlData)
        {
            // create an instance of a XmlSerializer class with the given type toDeserialize..
            XmlSerializer xmlSerializer = new XmlSerializer(toDeserialize);

            // construct a StringReader class instance of the given xmlData parameter to be deserialized by the XmlSerializer class instance..
            using (StringReader stringReader = new StringReader(xmlData))
            {
                // return the "new" object deserialized via the XmlSerializer class instance..
                return xmlSerializer.Deserialize(stringReader);
            }
        }
    }
}

0
Petteri Kautonen