2009-02-03 13 views
68

Quiero serializar mi valor enum como un int, pero solo obtengo el nombre.¿Cómo serializo un valor enum como un int?

Aquí es mi clase (muestra) y enumeración:

public class Request { 
    public RequestType request; 
} 

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

Y el código (sólo para estar seguro de que no estoy haciendo mal)

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 (a otra pregunta) parece indicar que las enumeraciones deben serializarse en ints como predeterminadas, pero no parece hacer eso. Aquí está mi salida:

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

he podido serializar como el valor poniendo "[XmlEnum (" X ")]" atributo en cada valor, pero esto sólo parece mal.

Respuesta

62

La mayoría de las veces, las personas quieren nombres, no ints. ¿Podría agregar una propiedad shim para este propósito?

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

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

O usted podría utilizar IXmlSerializable, pero eso es un montón de trabajo.

+0

Para que quede claro, lo que hace el fragmento es decirle al XmlSerializer: IGNORE la propiedad MyEnum. Y SERIALIZE la Propiedad FooInt32, que simplemente lanza el apuntador MyEnum a un valor Int32. Esto funcionará perfectamente para ti. – Cheeso

+0

Esta es una buena solución al hacer referencia a Enum's desde bibliotecas de terceros. – CtrlDot

+0

También se debe tener en cuenta que la propiedad FooInt32 se serializa como el nombre Foo.Me gusta más esta respuesta porque si tienes docenas de valores en tu enumeración, solo tienes que hacer esto una vez. –

-1

Eche un vistazo a la clase System.Enum. El método Parse convierte una cadena o una representación int en el objeto Enum y el método ToString convierte el objeto Enum en una cadena que se puede serializar.

+3

Aunque todo es cierto, eso no aborda cómo usarlo de forma transparente durante la serialización, que es el verdadero problema. –

13

Por favor, vea el ejemplo completo programa de aplicación de consola a continuación para una interesante manera de lograr lo que estás buscando usando 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); 
     } 
    } 
} 

El contenido de Request.txt son los siguientes después de la llamada a WriteObject :

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

usted necesitará una referencia al ensamblado System.Runtime.Serialization.dll para DataContractSerializer.

+0

La pregunta ya menciona el uso de [XmlEnum ("...")], el XmlSerializer equivalente a [EnumMember ("...")] - por lo que no estoy seguro de que esto agregue algo que el OP aún no sepa. –

+1

Además, dado que DataContractSerializer es compatible con miembros privados, el enfoque más simple sería una propiedad * private * shim que arroje entre 'int' y la enumeración. –

+0

Sí, me di cuenta de que re: XmlEnum gracias, pero como digo creo que es una solución interesante a la pregunta. Qué solución es "más simple" es subjetiva y, en última instancia, depende del encuestador. De acuerdo: con el enfoque 'shim' DataContractSerializer y su soporte para miembros privados es el camino a seguir –

125

La forma más sencilla es utilizar [XmlEnum] atribuir este modo:

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

Esto serializar en XML (dicen que la clase padre es CustomClass) de esta manera:

<CustomClass> 
    <EnumValue>2</EnumValue> 
</CustomClass> 
+0

Lo prefiero mucho porque es menos trabajo y más fácil de leer/comprender. Me gustaría ver una comparación de este método y la respuesta aceptada anteriormente –

+5

Es discutible si esto es realmente menos trabajo que la respuesta aceptada. Más valores enum = más mantenimiento. – youwhut

+2

+1 Este es también mi método preferido: ¿por qué crear una propiedad shim innecesaria cuando unas pocas directivas adicionales te permitirán (de) serializar Enum correctamente? – CJM

0

Puesto que usted están asignando valores explícitos no secuenciales a las opciones enum. Supongo que quieres poder especificar más de un valor a la vez (indicadores binarios), entonces la respuesta aceptada es tu única opción. Pasando en PreBooking | PreBookingConfirmation tendrá un valor entero de 9 y el serializador no podrá deserializarlo, pero lo fundirá con una propiedad shim pero funcionará bien. O tal vez simplemente te perdiste el valor de 3 :)

+2

Acabo de encontrar un amigo enum práctico llamado [Banderas] que le permite usar indicadores de bits y se serializan de nuevo a las opciones correctas ... –

1
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 
} 

El enfoque anterior funcionó para mí.