views:

2675

answers:

5

I want to serialize my enum-value as an int, but i only get the name.

Here is my (sample) class and enum:

public class Request {
 public RequestType request;
}

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

And the code (just to be sure i'm not doing it wrong)

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

This answer (to another question) seems to indicate that enums should serialize to ints as default, but it doesn't seem to do that. Here is my output:

<?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"&gt;
  <request>Confirmation</request>
</Request>

I have been able to serialize as the value by putting an "[XmlEnum("X")]" attribute on every value, but this just seems wrong.

+5  A: 

Most of the time, people want names, not ints. You could add a shim property for the purpose?

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

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

Or you could use IXmlSerializable, but that is lots of work.

Marc Gravell
Just so we're clear - what the snippet does is tell the XmlSerializer - IGNORE the MyEnum property. And SERIALIZE the FooInt32 Property, which just casts the MyEnum prop to an Int32 value. This will work perfectly for you.
Cheeso
A: 

Take a look at the System.Enum class. The Parse method converts a string or int representation into the Enum object and the ToString method converts the Enum object to a string which can be serialized.

Glenn
While all true, that doesn't address how to use that transparently during serialization, which is the real issue.
Marc Gravell
+1  A: 

Please see the full example Console Application program below for an interesting way to achieve what you're looking for using the 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);
        }
    }
}

The contents of request.txt are as follows after the call to WriteObject:

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

You'll need a reference to the System.Runtime.Serialization.dll assembly for DataContractSerializer.

Peter McGrattan
The question already notes the [XmlEnum("...")] usage, the XmlSerializer equivalent to [EnumMember("...")] - so I'm not sure this adds anything the OP doesn't already know.
Marc Gravell
Besides which - since DataContractSerializer supports private members, the simpler approach would be a *private* shim property that casts between `int` and the enum.
Marc Gravell
Yes I spotted that re:XmlEnum thanks but as I say I think it's an interesting solution to the question.Which solution is 'simpler' is subjective and ultimately up to the questioner surely.Agreed: with 'shim' approach DataContractSerializer and it's support for private members is the way to go
Peter McGrattan
+9  A: 

The easiest way is to use [XmlEnum] attribute like so:

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

This will serialize into XML (say that the parent class is CustomClass) like so:

<CustomClass>
  <EnumValue>2</EnumValue>
</CustomClass>
miha
I greatly prefer this as its less work and easier to read / understand. I'd like to see a comparison of this method and the above accepted answer
Allen
A: 

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

Jack