84 votes

Comment sérialiser la valeur d'un enum comme un int ?

Je veux sérialiser la valeur de mon enum comme un int, mais je n'obtiens que le nom.

Voici ma classe (exemple) et mon enum :

public class Request {
    public RequestType request;
}

public enum RequestType
{
    Booking = 1,
    Confirmation = 2,
    PreBooking = 4,
    PreBookingConfirmation = 5,
    BookingStatus = 6
}

Et le code (juste pour être sûr que je ne me trompe pas)

Request req = new Request();
req.request = RequestType.Confirmation;
XmlSerializer xml = new XmlSerializer(req.GetType());
StringWriter writer = new StringWriter();
xml.Serialize(writer, req);
textBox1.Text = writer.ToString();

Cette réponse (à une autre question) semble indiquer que les enums devraient être sérialisés en ints par défaut, mais cela ne semble pas être le cas. Voici mon résultat :

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

J'ai réussi à sérialiser la valeur en mettant un attribut "[XmlEnum("X")]" sur chaque valeur, mais cela ne semble pas correct.

157voto

miha Points 1266

La méthode la plus simple consiste à utiliser l'attribut [XmlEnum] comme suit :

[Serializable]
public enum EnumToSerialize
{
    [XmlEnum("1")]
    One = 1,
    [XmlEnum("2")]
    Two = 2
}

Cela va se sérialiser en XML (disons que la classe parente est CustomClass) comme ceci :

<CustomClass>
  <EnumValue>2</EnumValue>
</CustomClass>

0 votes

Je préfère de loin cette méthode, qui est moins contraignante et plus facile à lire et à comprendre. J'aimerais voir une comparaison entre cette méthode et la réponse acceptée ci-dessus.

5 votes

On peut se demander si cela représente réellement moins de travail que la réponse acceptée. Plus de valeurs d'énumération = plus de maintenance.

7 votes

+1 C'est aussi ma méthode préférée - pourquoi créer une propriété de shim inutile alors que quelques directives supplémentaires vous permettront de (dé)sérialiser l'Enum correctement.

75voto

Marc Gravell Points 482669

La plupart du temps, les gens veulent des noms, pas des ints. Vous pourriez ajouter une propriété shim à cet effet ?

[XmlIgnore]
public MyEnum Foo {get;set;}

[XmlElement("Foo")]
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public int FooInt32 {
    get {return (int)Foo;}
    set {Foo = (MyEnum)value;}
}

Ou vous pouvez utiliser IXmlSerializable mais c'est beaucoup de travail.

0 votes

Pour que les choses soient claires, ce que fait le snippet, c'est dire à XmlSerializer d'IGNORER la propriété MyEnum. Et de SERIALISER la propriété FooInt32, qui convertit simplement la propriété MyEnum en une valeur Int32. Cela fonctionnera parfaitement pour vous.

0 votes

Il s'agit d'une bonne solution pour référencer des Enum à partir de bibliothèques tierces.

0 votes

Il convient également de noter que la propriété FooInt32 est sérialisée sous le nom de Foo. Je préfère cette réponse car si vous avez des dizaines de valeurs dans votre enum, vous n'aurez à le faire qu'une seule fois.

14voto

Peter McG Points 6385

Veuillez consulter l'exemple complet de programme d'application console ci-dessous pour découvrir une façon intéressante d'obtenir ce que vous recherchez en utilisant le DataContractSerializer :

using System;
using System.IO;
using System.Runtime.Serialization;

namespace ConsoleApplication1
{
    [DataContract(Namespace="petermcg.wordpress.com")]
    public class Request
    {
        [DataMember(EmitDefaultValue = false)]
        public RequestType request;
    }

    [DataContract(Namespace = "petermcg.wordpress.com")]
    public enum RequestType
    {
        [EnumMember(Value = "1")]
        Booking = 1,
        [EnumMember(Value = "2")]
        Confirmation = 2,
        [EnumMember(Value = "4")]
        PreBooking = 4,
        [EnumMember(Value = "5")]
        PreBookingConfirmation = 5,
        [EnumMember(Value = "6")]
        BookingStatus = 6
    }

    class Program
    {
        static void Main(string[] args)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(Request));

            // Create Request object
            Request req = new Request();
            req.request = RequestType.Confirmation;

            // Serialize to File
            using (FileStream fileStream = new FileStream("request.txt", FileMode.Create))
            {
                serializer.WriteObject(fileStream, req);
            }

            // Reset for testing
            req = null;

            // Deserialize from File
            using (FileStream fileStream = new FileStream("request.txt", FileMode.Open))
            {
                req = serializer.ReadObject(fileStream) as Request;
            }

            // Writes True
            Console.WriteLine(req.request == RequestType.Confirmation);
        }
    }
}

Le contenu de request.txt est le suivant après l'appel à WriteObject :

<Request xmlns="petermcg.wordpress.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <request>2</request>
</Request>

Vous aurez besoin d'une référence à l'assemblage System.Runtime.Serialization.dll pour DataContractSerializer.

0 votes

La question mentionne déjà l'utilisation de [XmlEnum("...")], l'équivalent XmlSerializer de [EnumMember("...")] - donc je ne suis pas sûr que cela ajoute quelque chose que le PO ne sait pas déjà.

1 votes

Par ailleurs, étant donné que DataContractSerializer prend en charge les membres privés, l'approche la plus simple consisterait à créer un fichier de type privé la propriété de cale qui permet de couler entre int et l'enum.

0 votes

Oui, j'ai remarqué que re:XmlEnum merci mais comme je l'ai dit je pense que c'est une solution intéressante à la question. La solution qui est "plus simple" est subjective et dépend en fin de compte de la personne qui pose la question. Je suis d'accord : avec l'approche 'shim', DataContractSerializer et son support des membres privés est la solution à adopter.

0voto

Glenn Points 3787

Jetez un coup d'œil à la classe System.Enum. La méthode Parse convertit une chaîne ou une représentation int dans l'objet Enum et la méthode ToString convertit l'objet Enum en une chaîne qui peut être sérialisée.

3 votes

Bien que tout cela soit vrai, cela n'explique pas comment l'utiliser de manière transparente pendant la sérialisation, ce qui est le véritable problème.

0voto

Adriaan Davel Points 156

Puisque vous attribuez des valeurs explicites non séquentielles aux options de l'enum, je suppose que vous voulez pouvoir spécifier plusieurs valeurs à la fois (drapeaux binaires), alors la réponse acceptée est votre seule option. Passer dans PreBooking | PreBookingConfirmation aura une valeur entière de 9 et le sérialiseur ne sera pas capable de le désérialiser, le couler avec une propriété shim fonctionnera bien cependant. Ou peut-être avez-vous simplement manqué la valeur 3 :)

2 votes

Je viens de trouver un ami enum très pratique appelé [Flags] qui vous permet d'utiliser des drapeaux de bits et ils sont sérialisés dans les options correctes...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X