Wie serialisiere ich einen Aufzählungswert als int?

75

Ich möchte meinen Enum-Wert als int serialisieren, aber ich bekomme nur den Namen.

Hier ist meine (Beispiel-) Klasse und Aufzählung:

public class Request {
    public RequestType request;
}

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

Und der Code (nur um sicherzugehen, dass ich es nicht falsch mache)

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();

Diese Antwort (auf eine andere Frage) scheint darauf hinzudeuten, dass Enums standardmäßig in Ints serialisiert werden sollten, aber das scheint sie nicht zu tun. Hier ist meine Ausgabe:

<?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>

Ich konnte als Wert serialisieren, indem ich jedem Wert ein "[XmlEnum (" X ")]" - Attribut hinzufügte, aber dies scheint einfach falsch zu sein.

Espo
quelle

Antworten:

71

Meistens wollen die Leute Namen, keine Ints. Sie könnten zu diesem Zweck eine Shim-Eigenschaft hinzufügen?

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

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

Oder Sie könnten verwenden IXmlSerializable, aber das ist viel Arbeit.

Marc Gravell
quelle
Nur damit wir uns klar sind - das Snippet teilt dem XmlSerializer mit, dass die MyEnum-Eigenschaft ignoriert wird. Und SERIALISIEREN Sie die FooInt32-Eigenschaft, die nur die MyEnum-Requisite auf einen Int32-Wert umwandelt. Dies wird perfekt für Sie funktionieren.
Cheeso
Dies ist eine gute Lösung, wenn Sie auf Enums aus Bibliotheken von Drittanbietern verweisen.
CtrlDot
Es ist auch zu beachten, dass die FooInt32-Eigenschaft als Name Foo serialisiert ist. Diese Antwort gefällt mir am besten, denn wenn Sie Dutzende von Werten in Ihrer Aufzählung haben, müssen Sie dies nur einmal tun.
Intrepidis
Ich habe dies auch erfolgreich in einem WebHTTP (JSON) -Dienst verwendet. Die einzige Änderung besteht darin, dass das Attribut [XmlElement ("Foo")] durch [DataMember (Name = "Foo")] ersetzt wird
Dan Parsonson,
146

Am einfachsten ist es, das Attribut [XmlEnum] wie folgt zu verwenden:

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

Dies wird wie folgt in XML serialisiert (sagen wir, dass die übergeordnete Klasse CustomClass ist):

<CustomClass>
  <EnumValue>2</EnumValue>
</CustomClass>
miha
quelle
5
Es ist fraglich, ob dies tatsächlich weniger Arbeit ist als die akzeptierte Antwort. Mehr Enum-Werte = mehr Wartung.
Youwhut
5
+1 Dies ist auch meine bevorzugte Methode - warum eine unnötige Shim-Eigenschaft erstellen, wenn Sie mit ein paar zusätzlichen Anweisungen die Enum ordnungsgemäß (de) serialisieren können?
CJM
1
Es sei denn, Sie definieren explizit auch alle Kombinationen. Für kleine Flaggenaufzählungen ist dies eine Option.
xr280xr
2
+1 Ich persönlich finde dies eine elegantere Lösung als die akzeptierte Antwort. Auf diese Weise ist es auch einfacher, Wörterbücher zu serialisieren, in denen Aufzählungswerte als Schlüssel verwendet werden.
Alex
1
Tolles Zeug. Ich würde jedoch empfehlen, das SerializableAttribut zu löschen, da dies für die XML-Serialisierung nicht erforderlich ist.
Julealgon
13

Im folgenden Beispielprogramm für die Konsolenanwendung finden Sie eine interessante Möglichkeit, mit dem DataContractSerializer das zu erreichen, wonach Sie suchen:

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);
        }
    }
}

Der Inhalt von request.txt lautet nach dem Aufruf von WriteObject wie folgt:

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

Sie benötigen einen Verweis auf die Assembly System.Runtime.Serialization.dll für DataContractSerializer.

Peter McG
quelle
In der Frage wird bereits die Verwendung von [XmlEnum ("...")] erwähnt, der XmlSerializer entspricht [EnumMember ("...")]. Ich bin mir also nicht sicher, ob dies etwas hinzufügt, das das OP noch nicht kennt.
Marc Gravell
1
Außerdem - da DataContractSerializer private Mitglieder unterstützt, wäre der einfachere Ansatz eine private Shim-Eigenschaft, die zwischen intund der Aufzählung wechselt.
Marc Gravell
Ja, ich habe das bezüglich: XmlEnum entdeckt, danke, aber wie gesagt, ich denke, es ist eine interessante Lösung für die Frage. Welche Lösung "einfacher" ist, ist subjektiv und letztendlich dem Fragesteller sicher überlassen. Einverstanden: Mit dem Shim-Ansatz ist DataContractSerializer und die Unterstützung für private Mitglieder der
richtige
1
@MarcGravell, @Peter McGrattan: Ist hier etwas falsch daran, so etwas zu verwenden [EnumMember(Value = "1")]? Oder sollten wir immer mit der von Marc G vorgeschlagenen "Shim" -Eigenschaft gehen?
VoodooChild
2
using System.Xml.Serialization;

public class Request
{    
    [XmlIgnore()]
    public RequestType request;

    public int RequestTypeValue
    {
      get 
      {
        return (int)request;
      } 
      set
      {
        request=(RequestType)value; 
      }
    }
}

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

Der obige Ansatz hat bei mir funktioniert.

Abhishek
quelle
0

Schauen Sie sich die System.Enum-Klasse an. Die Parse-Methode konvertiert eine Zeichenfolge- oder Int-Darstellung in das Enum-Objekt und die ToString-Methode konvertiert das Enum-Objekt in eine Zeichenfolge, die serialisiert werden kann.

Glenn
quelle
3
Das stimmt zwar nicht, aber es geht nicht darum, wie man das während der Serialisierung transparent verwendet, was das eigentliche Problem ist.
Marc Gravell
0

Da Sie den Aufzählungsoptionen explizite nicht sequentielle Werte zuweisen, gehe ich davon aus, dass Sie mehr als einen Wert gleichzeitig angeben möchten (binäre Flags), ist die akzeptierte Antwort Ihre einzige Option. PreBooking übergeben | PreBookingConfirmation hat einen ganzzahligen Wert von 9 und der Serializer kann ihn nicht deserialisieren. Das Casting mit einer Shim-Eigenschaft funktioniert jedoch gut. Oder vielleicht hast du gerade den 3 Wert verpasst :)

Adriaan Davel
quelle
2
Ich habe gerade einen praktischen Enum-Freund namens [Flags] gefunden, mit dem Sie Bit-Flags verwenden können und die zu den richtigen Optionen zurückkehren ...
Adriaan Davel