Как сериализовать значение перечисления как int?

Я хочу сериализовать значение enum как 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();

Этот ответ (на другой вопрос), по-видимому, указывает, что перечисления должны сериализоваться в целые числа по умолчанию, но, похоже, этого не происходит. Вот мой результат:

<?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")]" для каждого значения, но это кажется неправильным.


person Espo    schedule 03.02.2009    source источник


Ответы (6)


В большинстве случаев людям нужны имена, а не целые числа. Вы могли бы добавить свойство shim для этой цели?

[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, но это много работы.

person Marc Gravell    schedule 03.02.2009
comment
Чтобы было ясно: этот фрагмент сообщает XmlSerializer — IGNORE свойство MyEnum. И СЕРИАЛИЗУЙТЕ свойство FooInt32, которое просто преобразует свойство MyEnum в значение Int32. Это будет работать идеально для вас. - person Cheeso; 26.02.2009
comment
Это хорошее решение при обращении к Enum из сторонних библиотек. - person CtrlDot; 22.01.2012
comment
Следует также отметить, что свойство FooInt32 сериализуется как имя Foo. Мне нравится этот ответ больше всего, потому что, если у вас есть десятки значений в вашем перечислении, вам нужно сделать это только один раз. - person intrepidis; 23.03.2016
comment
Я также успешно использовал это в службе WebHTTP (JSON), с единственным изменением в том, что атрибут [XmlElement(Foo)] заменен на [DataMember(Name=Foo)] - person Dan Parsonson; 10.11.2017

Самый простой способ — использовать атрибут [XmlEnum] следующим образом:

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

Это будет сериализовано в XML (скажем, родительским классом является CustomClass) следующим образом:

<CustomClass>
  <EnumValue>2</EnumValue>
</CustomClass>
person miha    schedule 08.04.2009
comment
Я очень предпочитаю это, так как в нем меньше работы и его легче читать/понимать. Я хотел бы увидеть сравнение этого метода и приведенного выше принятого ответа. - person Allen Rice; 27.01.2010
comment
Спорно, действительно ли это меньше работы, чем принятый ответ. Больше значений перечисления = больше обслуживания. - person youwhut; 21.12.2010
comment
+1 Это также мой предпочтительный метод - зачем создавать ненужное свойство прокладки, когда несколько дополнительных директив позволят вам правильно (де) сериализовать Enum. - person CJM; 02.06.2011
comment
Если вы также явно не определите все комбинации. Для перечислений с маленькими флагами это вариант. - person xr280xr; 24.10.2012
comment
+1 Лично я считаю это более элегантным решением, чем принятый ответ. Таким образом также проще сериализовать словари, в которых значения перечисления используются в качестве ключей. - person Alex; 06.06.2013
comment
Отличный ответ. Именно то, что я искал. Просто и понятно! - person Kelsey; 08.05.2015
comment
Отличный материал. Я бы порекомендовал удалить атрибут Serializable, поскольку он не нужен для сериализации Xml. - person julealgon; 19.09.2017

Пожалуйста, ознакомьтесь с полным примером программы консольного приложения ниже, чтобы узнать об интересном способе достижения того, что вы ищете, с помощью 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);
        }
    }
}

Содержимое request.txt после вызова WriteObject выглядит следующим образом:

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

Вам понадобится ссылка на сборку System.Runtime.Serialization.dll для DataContractSerializer.

person Peter McG    schedule 03.02.2009
comment
В вопросе уже отмечается использование [XmlEnum(...)], XmlSerializer эквивалентен [EnumMember(...)] - поэтому я не уверен, что это добавляет что-то, чего OP еще не знает. - person Marc Gravell; 03.02.2009
comment
Кроме того, поскольку DataContractSerializer поддерживает закрытые члены, более простым подходом будет свойство private shim, которое приводит между int и перечислением. - person Marc Gravell; 03.02.2009
comment
Да, я заметил это re:XmlEnum, спасибо, но, как я уже сказал, я думаю, что это интересное решение вопроса. Какое решение является «более простым», субъективно и, в конечном счете, конечно же, зависит от вопрошающего. Согласен: с подходом «shim» DataContractSerializer и его поддержка частных членов - это путь. - person Peter McG; 03.02.2009
comment
@MarcGravell, @Peter McGrattan: так есть ли что-то неправильное в использовании [EnumMember(Value = "1")] таким образом? Или мы всегда должны использовать свойство shim, как предложил Марк Г.? - person VoodooChild; 28.02.2012

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
}

Вышеупомянутый подход работал для меня.

person Abhishek    schedule 14.09.2017

Взгляните на класс System.Enum. Метод Parse преобразует строковое или целочисленное представление в объект Enum, а метод ToString преобразует объект Enum в строку, которую можно сериализовать.

person Glenn    schedule 03.02.2009
comment
Хотя все это правда, это не касается того, как использовать это прозрачно во время сериализации, что является реальной проблемой. - person Marc Gravell; 03.02.2009

Поскольку вы назначаете явные непоследовательные значения параметрам перечисления, я предполагаю, что вы хотите иметь возможность указывать более одного значения за раз (двоичные флаги), тогда принятый ответ - ваш единственный вариант. Прохождение предварительного бронирования | PreBookingConfirmation будет иметь целочисленное значение 9, и сериализатор не сможет его десериализовать, однако приведение его со свойством shim будет работать хорошо. Или, может быть, вы просто пропустили значение 3 :)

person Adriaan Davel    schedule 08.02.2012
comment
Я только что нашел удобного друга enum под названием [Flags], который позволяет вам использовать битовые флаги, и они сериализуются обратно к правильным параметрам... - person Adriaan Davel; 08.02.2012