views:

263

answers:

3

I am looking to return the following class through a web service, which includes an enum type as one of its members.

[Serializable, XmlRoot("GeoCoordinate")]
public class GeoCoordinate
{
    public enum AccuracyLevel
    {
        Unknown = 0,
        Country = 1,
        Region = 2,
        SubRegion = 3,
        Town = 4,
        PostalCode = 5,
        Street = 6,
        Intersection = 7,
        Address = 8,
        Premise = 9
    }

    private AccuracyLevel _accuracy;

    // ... more members


    public AccuracyLevel Accuracy
    {
        get { return _accuracy; } 
        set { _accuracy = value;}
    }
}

This works correctly, but will return a result in the form of:

<!-- ... -->
<Accuracy>Unknown or Country or Region or SubRegion or Town or 
  PostalCode or Street or Intersection or Address or Premise</Accuracy>
<!-- ... -->

Instead of a string that represents the enum, I would like it to simply return an integer. Can this be done without changing the type of GeoCoordinate.Accuracy?

+1  A: 

Decorate the enum with [Serializable] or [DataContract]. There are some differences between the two attributes, make sure you check it out (this blog post may help with that). And mark the individual enum items with [EnumMember]. I have never checked what the enum looks like in transit, but doing this will ensure that it arrives at the other end, and will also ensure that it gets picked up if you generate a client side proxy.

slugster
`DataContract` and `EnumMember` has always worked for me.
Nate Bross
None of these options seem to change the manner in which this field is serialized.
Mike
Yeah, i think that when it comes to WCF it makes no difference, but it does if you are serializing to XML? I would welcome anyone giving a simple bullet explanation of the differences.
slugster
+2  A: 

I believe you'll need to use [XmlIgnore] on the enum, and create a second property which returns the integer value:

[XmlRoot("GeoCoordinate")]
public class GeoCoordinate
{
    public enum AccuracyLevel
    {
        Unknown = 0,
        Country = 1,
        Region = 2,
        SubRegion = 3,
        Town = 4,
        PostalCode = 5,
        Street = 6,
        Intersection = 7,
        Address = 8,
        Premise = 9
    }

    private AccuracyLevel _accuracy;

    // ... more members


    [XmlIgnore]
    public AccuracyLevel Accuracy
    {
        get { return _accuracy; } 
        set { _accuracy = value;}
    }

    [XmlElement("AccuracyLevel")]
    public int AccuracyLevelInt
    {
        get {return (int) AccuracyLevel;}
        set {AccuracyLevel = (AccuracyLevel) value;}
    }
}

Note that [Serializable] is not used by the XML Serializer.

Also, note that the AccuracyLevelInt property is probably implemented incorrectly. I'm looking into that now.

John Saunders
This would work, but I was hoping to avoid creating another property (perhaps through an Xml attribute on GeoCoordinate.Accurate, but it seems like this doesn't exist.)
Mike
+1  A: 

Although it is a hack, I deemed using XmlEnumAttribute on each of the enum members to be most pallatable in this case. If this enum were much larger, it would probably be better to use XmlIgnore on the Accuracy property, and add an additional int property to the class as described in another answer to this question.

Usng XmlEnumAttribute means that only the enum itself needs to be modified, and will xml serialize like an int wherever it is used.

    public enum AccuracyLevel
    {
        [XmlEnum("0")] Unknown = 0,
        [XmlEnum("1")] Country = 1,
        [XmlEnum("2")] Region = 2,
        [XmlEnum("3")] SubRegion = 3,
        [XmlEnum("4")] Town = 4,
        [XmlEnum("5")] PostalCode = 5,
        [XmlEnum("6")] Street = 6,
        [XmlEnum("7")] Intersection = 7,
        [XmlEnum("8")] Address = 8,
        [XmlEnum("9")] Premise = 9
    }
Mike
I prefer this over Saunderses answer
Allen