Pytanie w sprawie deserialization, versioning, serialization, xml, c# – XmlSerializer: Jak odserializować wartość wyliczoną, która już nie istnieje

8

Używam XMLSerializer, aby zapisać tę klasę do pliku. Klasa ma łańcuch i wyliczenie, jak pokazano poniżej:

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


public enum TypeEnum
{
    Temperature,
    Pressure,
    Humidity,
}

Po serializacji wygląda to tak.

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

Szeregowałem i deserializowałem ten obiekt bez żadnych problemów dla kilku wersji. Nie chcę już obsługiwać wilgotności, więc usunąłem ją z enum. Powoduje to jednak wyjątek podczas deserializacji z XML, ponieważ wartość w polu TypeEnum, Wilgotność, nie jest poprawną wartością dla TypeEnum. To ma sens, ale jak sobie z tym poradzić?

Chciałbym po prostu zignorować ten błąd. I pozostaw wartość jako null. Próbowałem zaimplementować klasę XmlDeserilizationEvent OnUnknownElement. Niestety, nie łapie tego błędu.

Wszelkie pomysły na złapanie i zignorowanie tego błędu (mogę oczyścić po zakończeniu deserializacji).

Mitch

Jeśli znalazłeś rozwiązanie, które chciałbym wiedzieć. Mam pokrewny problem, w którym strona serwera zawiera nową wartość flagi enum, o której klient nie wie, więc naprawdę chcę znaleźć sposób na zarządzanie serializacją tylko jednego pola. Następnym razem użyję int, ale na razie ... kompatybilności wstecznej. avenmore

Twoja odpowiedź

4   odpowiedź
2

aby zmienić nazwy węzłów wokół i ukryć elementy z serializacji xml, analizując tylko jeden element ręcznie:

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)
   {
   }
  }
 }
}

Według komentarzy wydaje się, że istnieje pewne zamieszanie;Oto działający przykład jako projekt Visual Studio 2010. Podejście to jest prostym sposobem ręcznego analizowania tylko jednej właściwości obiektu (nadal wykorzystując XmlSerializer do przetwarzania składni XML).

Szeregowanie wartości wyliczeniowej jako ciągu zamiast enum byłoby dobrym pomysłem, jeśli nie miałem jeszcze plików XML, które muszę przeczytać. Te istniejące pliki mają element <TypeEnum> i nadal muszę odczytać wartość pola TypeEnum i odpowiednio działać. Idealnym rozwiązaniem byłoby złapanie wyjątku, gdy próbuje on rozszeregować wartość wilgotności. Ale żaden z programów obsługi wyjątków, które umieściłeś w deserializerze, nie przechwycił tego błędu. Mitch
Dołączyłem próbkę do skompilowania, aby pokazać, że działa i jak działa. user423430
5

Możesz oznaczyć członka Przestarzałe

public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}
Powodem, dla którego nie mogę użyć atrybutu [Przestarzałe] jest to, że powszechną praktyką w naszym kodzie jest iterowanie wartości wyliczeń. Więc nawet jeśli „Wilgotność” jest oznaczona jako przestarzała, nadal byłaby ona wychwytywana w naszych pętlach foreach. (Chyba że istnieje sposób na zastąpienie modułu wyliczającego?) Mitch
Czy możesz ustawić zmienną null gdziekolwiek ją używasz? np. TypeEnum? val = null; user3362735
4

że niewłaściwą praktyką jest usuwanie członka wyliczenia po tym, jak biblioteka jest już w użyciu. Dlaczego nie zostawisz członka na miejscu, ale zaznacz go symbolem[Obsolete] atrybut, aby zapobiec przyszłemu użyciu? OkreślanieObsoleteAttribute(string,bool) drugi parametr konstruktora jakotrue spowodowałoby błąd podczas kompilacji, jeśli zaznaczony element jest dostępny.

public enum TypeEnum
{
    Temperature,
    Pressure,

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

Aby obejść błąd podczas sprawdzania wartości zserializowanych, można porównać z wartością bazową:typeEnum == (TypeEnum)2.

1

IXmlSerializowalny, gdzie możesz użyć czegoś takiego jak TryParse dla enum.

Ale zgadzam się z innymi plakatami, używając atrybutu Przestarzałe.

Jeśli nie mogę znaleźć innego obejścia, niestandardowa serializacja za pomocą IXMLSerializable może być jedynym rozwiązaniem. Gdy już to robię, dodam także pole wersji, które mogłem wykorzystać do kierowania deserializacją. Robimy coś podobnego, gdy używamy ISerializable. Prawdziwa klasa ma około 15 pól. Zastanawiam się, czy mógłbym uciec z pisaniem kodu deserializatora dla jednego pola? Mitch

Powiązane pytania