Frage an serialization, xml, c#, versioning, deserialization – XmlSerializer: So deserialisieren Sie einen nicht mehr vorhandenen Enum-Wert

8

Ich verwende den XMLSerializer, um diese Klasse in einer Datei zu speichern. Die Klasse hat eine Zeichenfolge und eine Aufzählung wie folgt:

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


public enum TypeEnum
{
    Temperature,
    Pressure,
    Humidity,
}

Wenn es serialisiert ist, sieht es so aus.

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

Ich habe dieses Objekt für mehrere Versionen ohne Probleme serialisiert und deserialisiert. Ich möchte Humidity nicht länger unterstützen, deshalb habe ich es aus der Enumeration entfernt. Dies führt jedoch zu einer Ausnahme bei der Deserialisierung aus XML, da der Wert im Feld TypeEnum, Humidity, kein gültiger Wert für TypeEnum ist. Das macht Sinn, aber wie geht man damit um?

Ich möchte diesen Fehler einfach ignorieren. Und belassen Sie den Wert auf null. Ich habe versucht, die OnUnknownElement XmlDeserilizationEvent-Klasse zu implementieren. Leider wird dieser Fehler dadurch nicht abgefangen.

Irgendwelche Ideen, wie man diesen Fehler abfängt und ignoriert (ich kann aufräumen, nachdem die Deserialisierung abgeschlossen ist).

Mitch

Wenn Sie eine Lösung gefunden haben, würde ich gerne wissen. Ich habe ein verwandtes Problem, bei dem der Server einen neuen Enum-Flag-Wert enthält, von dem der Client nichts weiß, und daher wirklich einen Weg finden möchte, die Serialisierung nur dieses einen Felds zu verwalten. Nächstes Mal verwende ich nur ein int, aber vorerst ... Abwärtskompatibilität. avenmore

Deine Antwort

4   die antwort
4

ein Enumerationsmitglied zu entfernen, nachdem Ihre Bibliothek bereits verwendet wird. Warum lassen Sie das Mitglied nicht an Ort und Stelle, sondern markieren es mit dem[Obsolete] Attribut, um zukünftige Verwendung zu verhindern? Angeben derObsoleteAttribute(string,bool) zweiter Parameter des Konstruktors alstrue würde einen Fehler beim Kompilieren verursachen, wenn auf das markierte Element zugegriffen wird.

public enum TypeEnum
{
    Temperature,
    Pressure,

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

Um den Fehler beim Überprüfen deserialisierter Werte zu umgehen, können Sie den zugrunde liegenden Wert vergleichen:typeEnum == (TypeEnum)2.

1

IXmlSerializable, wo Sie so etwas wie TryParse für die Aufzählung verwenden können.

Ich stimme jedoch den anderen Postern mit dem Attribut "Veraltet" zu.

Wenn ich keine andere Problemumgehung finde, ist die benutzerdefinierte Serialisierung mit IXMLSerializable die einzige Lösung. Während ich dabei bin, würde ich auch ein Versionsfeld hinzufügen, das ich verwenden könnte, um die Deserialisierung zu steuern. Wir machen etwas Ähnliches, wenn wir ISerializable verwenden. Die reale Klasse hat ungefähr 15 Felder. Ich frage mich, ob ich es schaffen könnte, nur den Deserializer-Code für das eine Feld zu schreiben. Mitch
5

Sie können das Mitglied als veraltet markieren

public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}
Können Sie die Variable auf Null setzen, wo immer Sie sie verwenden? z.B. TypeEnum? val = null; user3362735
Der Grund, warum ich das Attribut [Veraltet] nicht verwenden kann, ist, dass es in unserem Code üblich ist, die Enum-Werte zu durchlaufen. Selbst wenn "Luftfeuchtigkeit" als veraltet markiert ist, wird sie dennoch in unseren foreach-Schleifen erfasst. (Es sei denn, es gibt eine Möglichkeit, den Enumerator zu überschreiben?) Mitch
2

um Knotennamen zu ändern und Elemente aus der XML-Serialisierung auszublenden, indem Sie nur dieses eine Element manuell analysieren:

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

Laut Kommentaren scheint es einige Verwirrung zu geben;Hier ist ein Beispiel als Visual Studio 2010-Projekt. Dieser Ansatz ist eine einfache Methode, um nur eine Eigenschaft eines Objekts manuell zu analysieren (wobei der XmlSerializer weiterhin für die XML-Analyse verwendet wird).

Ich habe ein kompilierbares Beispiel beigefügt, um zu demonstrieren, dass es funktioniert und wie es funktioniert. user423430
Das Serialisieren des Aufzählungswerts als Zeichenfolge anstelle der Aufzählung ist eine gute Idee, wenn ich nicht bereits über XML-Dateien verfügt habe, die ich lesen muss. Diese vorhandenen Dateien haben das <TypeEnum \> -Element, und ich muss den Wert des TypeEnum-Felds noch lesen und entsprechend handeln. Eine ideale Lösung wäre, die Ausnahme abzufangen, wenn versucht wird, den Feuchtigkeitswert zu deserialisieren. Keiner der Ausnahmehandler, die Sie in den Deserializer eingefügt haben, hat diesen Fehler abgefangen. Mitch

Verwandte Fragen