2012-05-22 4 views
8

Ich verwende den XMLSerializer, um diese Klasse in einer Datei zu speichern. Die Klasse hat eine Zeichenkette und eine Enumeration, wie unten gezeigt:XmlSerializer: Wie ein Enum-Wert deserialize, der nicht mehr existiert

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


public enum TypeEnum 
{ 
    Temperature, 
    Pressure, 
    Humidity, 
} 

Wenn serialisiert, 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 nicht länger Feuchtigkeit unterstützen, also habe ich sie aus dem Enum entfernt. Dies führt jedoch zu einer Ausnahme beim Deserialisieren aus XML, da der Wert im TypeEnum-Feld Humidity kein gültiger Wert für TypeEnum ist. Das macht Sinn, aber wie geht das?

Was ich tun möchte, ist diesen Fehler einfach zu ignorieren. Und belassen Sie den Wert als null. Ich habe versucht, die OnUnknownElement XmlDeserilizationEvent-Klasse zu implementieren. Leider fängt dies diesen Fehler nicht ein.

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

Mitch

+0

Wenn Sie eine Lösung gefunden haben würde ich gerne wissen. Ich habe ein verwandtes Problem, bei dem die Serverseite einen neuen Enum-Flag-Wert enthält, über den der Client nichts weiß, also möchte ich wirklich einen Weg finden, die Serialisierung nur dieses einen Feldes zu verwalten. Das nächste Mal werde ich nur eine int, aber für jetzt ... Rückwärtskompatibilität verwenden. – avenmore

Antwort

5

können Sie das Element markieren Obsolete

public enum TypeEnum 
{ 
    Temperature, 
    Pressure, 
    [Obsolete] 
    Humidity 
} 
+2

Der Grund, warum ich das [Obsolete] -Attribut nicht verwenden kann, liegt darin, dass es in unserem Code üblich ist, die Enum-Werte zu durchlaufen. Auch wenn "Feuchtigkeit" als veraltet markiert ist, wird es trotzdem in unseren foreach-Schleifen aufgenommen. (Es sei denn, es gibt eine Möglichkeit, den Enumerator zu überschreiben?) – Mitch

+0

Können Sie die Variable auf Null setzen, wo immer Sie sie verwenden? z. B. TypeEnum?val = null; –

4

Es ist allgemein schlechte Praxis betrachtet eine Enumerationsmember nach Ihrer Bibliothek ist bereits im Einsatz zu entfernen. Warum lassen Sie das Mitglied nicht an Ort und Stelle, sondern markieren Sie es mit dem Attribut [Obsolete], um eine zukünftige Verwendung zu verhindern? Die Angabe des zweiten Parameters des ObsoleteAttribute(string,bool) Konstruktors als true würde einen Kompilierungsfehler 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 zu umgehen, wenn deserialisiert Werte überprüft, Sie gegen den zugrunde liegenden Wert vergleichen könnte: typeEnum == (TypeEnum)2.

1

Sie könnten IXmlSerializable implementieren, wo Sie etwas wie TryParse für die Enumeration verwenden können.

Aber ich stimme den anderen Plakaten zu, die das Obsolete-Attribut verwenden.

+0

Wenn ich keine andere Problemumgehung finden kann, kann die benutzerdefinierte Serialisierung mit IXMLSerializable die einzige Lösung sein. Während ich dabei bin, würde ich auch ein Versionsfeld hinzufügen, mit dem ich die Deserialisierung steuern könnte. Wir machen etwas ähnliches bei der Verwendung von ISerializable. Die echte Klasse hat ungefähr 15 Felder. Ich frage mich, ob ich damit durchkommen könnte, nur Deserializer-Code für das eine Feld zu schreiben? – Mitch

2

Sie Attribute verwenden können, um um Knotennamen zu ändern und Elemente aus XML-Serialisierung verstecken, Parsen nur, dass ein Element manuell:

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

Pro Kommentare scheint es einige Verwirrung zu sein; here is a worked example als ein Visual Studio 2010-Projekt. Dieser Ansatz ist eine einfache Möglichkeit, nur eine Eigenschaft eines Objekts manuell zu analysieren (wobei der XmlSerializer weiterhin für die XML-Analyse verwendet wird).

+0

Serialisieren des Enum-Werts als String anstelle des Enums, wäre eine gute Idee, wenn ich nicht schon XML-Dateien hätte, die ich lesen muss. Diese vorhandenen Dateien haben das Element und ich muss immer noch den Wert des TypeEnum-Felds lesen und entsprechend handeln. Eine ideale Lösung wäre, die Ausnahme abzufangen, wenn versucht wird, den Luftfeuchtigkeitswert zu deserialisieren. Aber keiner der Ausnahme-Handler, die Sie auf dem Deserializer setzen, fangen diesen Fehler ein. – Mitch

+0

Ich habe ein kompilierbares Beispiel hinzugefügt, um zu zeigen, dass es funktioniert und wie es funktioniert. – user423430

Verwandte Themen