如何将枚举值序列化为int?


75

我想将我的enum-value序列化为一个int,但是我只知道名字。

这是我的(示例)类和枚举:

public class Request {
    public RequestType request;
}

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

和代码(只是为了确保我没有做错)

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

这个答案(针对另一个问题)似乎表明默认情况下枚举应序列化为ints,但似乎没有这样做。这是我的输出:

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

通过在每个值上放置一个[[XmlEnum(“ X”)]“属性,我已经能够将其序列化为值,但这似乎是错误的。

Answers:


71

大多数时候,人们想要的是名字,而不是整数。您可以为此目的添加垫片属性吗?

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

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

或者,您可以使用IXmlSerializable,但这需要大量工作。


就是这样,我们很清楚-代码段的作用是告诉XmlSerializer-忽略MyEnum属性。然后序列化FooInt32属性,该属性只是将MyEnum prop转换为Int32值。这将完全适合您。
Cheeso

当引用来自第三方库的Enum时,这是一个很好的解决方案。
CtrlDot 2012年

还应注意,FooInt32属性被序列化为名称Foo。我最喜欢这个答案,因为如果您的枚举中包含数十个值,则只需执行一次。
intrepidis

我还在WebHTTP(JSON)服务中成功使用了此方法,唯一的变化是[XmlElement(“ Foo”)]属性替换为[DataMember(Name =“ Foo”)]
Dan Parsonson

146

最简单的方法是使用[XmlEnum]属性,如下所示:

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

这将序列化为XML(例如,父类为CustomClass),如下所示:

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

5
是否实际上比接受的答案少工作是有争议的。更多的枚举值=更多的维护。
youwhut 2010年

5
+1这也是我的首选方法-为什么当一些额外的指令将允许您正确地对Enum(反序列化)时创建不必要的shim属性。
CJM,

1
除非您也明确定义所有组合。对于小标志枚举,这是一个选择。
xr280xr 2012年

2
+1就个人而言,我认为这是比接受的答案更优雅的解决方案。这样,将枚举值用作键的字典进行序列化也更容易。
亚历克斯

1
好东西。我建议您删除该Serializable属性,尽管这对于Xml序列化不是必需的。
julealgon

13

请参阅下面的完整示例控制台应用程序程序,以有趣的方式使用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);
        }
    }
}

调用WriteObject之后,request.txt的内容如下:

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

您需要对DataContractSerializer的System.Runtime.Serialization.dll程序集的引用。


该问题已经说明了[XmlEnum(“ ...”)]的用法,等效于[EnumMember(“ ...”)]的XmlSerializer-因此,我不确定这会添加OP尚不知道的内容。
Marc Gravell

1
除此之外-由于DataContractSerializer支持私有成员,因此更简单的方法是在枚举与枚举之间转换的私有shim属性int
马克·格雷韦尔

是的,我发现了re:XmlEnum,谢谢,但是正如我所说,我认为这是一个有趣的解决方案。哪种解决方案“更简单”是主观的,并最终取决于提问者。同意:采用“ shim”方法DataContractSerializer及其对私有成员的支持是必经之路
Peter McG

1
@ MarcGravell,@ Peter McGrattan:那么使用这种方法有什么问题[EnumMember(Value = "1")]吗?还是我们应该始终按照Marc G的建议使用“ shim”属性?
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
}

上面的方法对我有用。


0

看一下System.Enum类。Parse方法将字符串或int表示形式转换为Enum对象,而ToString方法将Enum对象转换为可以序列化的字符串。


3
虽然都是如此,但这并没有解决如何在序列化期间透明地使用它,这是真正的问题。
Marc Gravell

0

由于您要为枚举选项分配显式的非顺序值,所以我假设您希望一次可以指定多个值(二进制标志),那么可接受的答案是您唯一的选择。传递预定书| PreBookingConfirmation将具有9的整数值,并且序列化程序将无法对其进行反序列化,但使用shim属性强制转换它会很好。或者,也许您只是错过了3个值:)


2
我刚刚找到了一个方便的枚举朋友,名称为[Flags],可让您使用位标志并将其序列化为正确的选项...
Adriaan Davel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.