Вопрос по c#, xml – XmlSerializer: как десериализовать значение перечисления, которое больше не существует

8

Я использую XMLSerializer для сохранения этого класса в файл. У класса есть строка и перечисление, как показано ниже:

public class IOPoint
{
     string Name {get; set;}
     TypeEnum {get; set;}
}


public enum TypeEnum
{
    Temperature,
    Pressure,
    Humidity,
}

Когда сериализуется, это выглядит так.

<IOPoint>
  <Name>Relative Humidity</Name>
  <TypeEnum>Humidity</TypeEnum>
</IOPoint>

Я сериализовал и десериализовал этот объект без проблем для нескольких версий. Я больше не хочу поддерживать влажность, поэтому я удалил ее из перечисления. Однако это вызывает исключение при десериализации из XML, поскольку значение в поле TypeEnum, Humidity, не является допустимым значением для TypeEnum. Это имеет смысл, но как справиться с этим?

То, что я хотел бы сделать, это просто игнорировать эту ошибку. И оставьте значение как ноль. Я пытался реализовать класс OnUnknownElement XmlDeserilizationEvent. К сожалению, это не ловит эту ошибку.

Любые идеи о том, как отловить и игнорировать эту ошибку (я могу исправить после завершения десериализации).

Митч

Если бы вы нашли решение, которое я хотел бы узнать. У меня есть проблема, связанная с тем, что на стороне сервера есть новое значение флага enum, о котором клиент не знает, поэтому очень хочу найти способ управления сериализацией только одного этого поля. В следующий раз я просто буду использовать int, но пока ... обратная совместимость. avenmore

Ваш Ответ

4   ответа
5

Вы можете пометить участника как устаревшего

public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}
Причина, по которой я не могу использовать атрибут [Устаревший], заключается в том, что в нашем коде принято перебирать значения перечисления. Таким образом, даже если «Влажность» помечена как устаревшая, она все равно будет обнаружена в наших циклах foreach. (Разве есть способ переопределить перечислитель?) Mitch
Можете ли вы сделать переменную нулевой везде, где вы ее используете? например, TypeEnum? val = ноль; user3362735
4

как ваша библиотека уже используется. Почему вы не оставляете участника на месте, а пометьте его знаком[Obsolete] атрибут для предотвращения использования в будущем? УказаниеObsoleteAttribute(string,bool)торой параметр конструктора @ какtrue вызовет ошибку во время компиляции, если к отмеченному элементу будет получен доступ.

public enum TypeEnum
{
    Temperature,
    Pressure,

    [Obsolete("It's always sunny in Philadelphia", true)]
    Humidity,
}

Чтобы обойти ошибку при проверке десериализованных значений, вы можете сравнить с базовым значением:typeEnum == (TypeEnum)2.

2

ментов от сериализации xml, анализируя только один этот элемент вручную:

public class IOPoint
{
 public string Name {get; set;}

 [XmlIgnore]
 public TypeEnum TypeEnum {get; set;}

 [XmlElement("TypeEnum")]
 public string LegacyTypeEnum 
 {
  get { return this.TypeEnum.ToString(); }
  set 
  { 
   try
   {
    this.TypeEnum = (TypeEnum)Enum.Parse(typeof(TypeEnum),value);
   }
   catch(ArgumentException)
   {
    // Handle "Humidity"
   }
   catch(OverflowException)
   {
   }
  }
 }
}

Per комментарии, кажется, некоторая путаница; Вот пример работы как проект Visual Studio 2010. Этот подход представляет собой простой способ синтаксического анализа только одного свойства объекта (все еще используя XmlSerializer для анализа XML).

Я включил скомпилированный пример, чтобы продемонстрировать, как он работает, и как он работает. user423430
Сериализация значения перечисления в виде строки вместо перечисления будет хорошей идеей, если у меня еще не было файлов XML, которые мне нужно прочитать. Эти существующие файлы имеют элемент <TypeEnum \>, и мне все еще нужно прочитать значение поля TypeEnum и действовать соответственно. Идеальным решением было бы поймать исключение при попытке десериализации значения влажности. Но ни один из обработчиков исключений, которые вы добавили в десериализатор, не уловит эту ошибку. Mitch
1

IXmlSerializable, где вы можете использовать что-то вроде TryParse для перечисления.

Но я согласен с другими авторами, использующими атрибут "Устаревший".

Если я не могу найти другого обходного пути, пользовательская сериализация с использованием IXMLSerializable может быть единственным решением. Пока я в этом, я бы также добавил поле Версия, которое я мог бы использовать для направления десериализации. Мы делаем нечто подобное при использовании ISerializable. В реальном классе около 15 полей. Интересно, смогу ли я просто написать код десериализатора для одного поля? Mitch

Похожие вопросы