5

Per semplicità, mostrerò il mio codice di esempio utilizzando la frutta. In realtà sto facendo qualcosa di più significativo (speriamo). Cerchiamo di dire che abbiamo un enum:Come evitare l'eccezione deserializzando un oggetto enum non valido?

public enum FruitType 
{ 
    Apple, 
    Orange, 
    Banana 
} 

e una classe:

[Serializable] 
public class Fruit 
{ 
    public FruitType FruitType { get; set; } 
    public Fruit(FruitType type) 
    { 
     this.FruitType = type; 
    } 
} 

Siamo in grado di serializzare e de-serializzare esso. Ora, consente di rivedere l'enum, in modo che sia ora:

public enum FruitType 
{ 
    GreenApple, 
    RedApple, 
    Orange, 
    Banana 
} 

Quando de-serializzazione di oggetti precedentemente serializzati, si ottiene un'eccezione System.InvalidOperation come Apple (voce enum originale) non è valido. L'oggetto non viene de-serializzato.

Un modo sono stato in grado di risolvere questo è stato quello di dare la proprietà FruitType nella classe Fruit un nome diverso quando viene serializzato come segue:

[XmlElement(ElementName = "Mode")] 
    public FruitType FruitType { get; set; } 

Ora, durante la de-serializzazione la vecchia proprietà viene ignorato come non è stato trovato Vorrei sapere se esiste un modo per ignorare/saltare elementi di enum non validi durante la de-serializzazione, in modo che non venga generata alcuna eccezione e l'oggetto continui a essere de-serializzato.

+1

Vedere la mia risposta alla domanda collegata in cui includo un progetto di esempio di lavoro: http://stackoverflow.com/a/10709040 – user423430

risposta

3

Lasciare Apple e contrassegnarlo con ObsoleteAttribute. In questo modo, qualsiasi codice che utilizza Apple genererà un avviso del compilatore.

+0

Ho aggiunto [Obsoleto] sopra l'elemento enum 'Apple'. Tuttavia, ottengo ancora la seguente eccezione durante la deserializzazione e l'oggetto precedente: Errore di convalida dell'istanza: "Apple" non è un valore valido per FruitType. – Elan

0

Ho inviato un similar question e non ho trovato un metodo semplice per rilevare l'eccezione generata quando il deserializzatore incontra Apple nel file XML. Posso cogliere un sacco di altre eccezioni durante la deserializzazione per attributi o elementi mancanti, ma non per un valore enum non valido. Il valore enum non valido (nel tuo caso Apple) mi fa uscire dalla deserializzazione.

Una possibile soluzione è implementare IXMLSerializable nella classe Fruit. Quando il metodo IXMLSerailizable.ReadXML() viene chiamato dal deserializzatore, dovrai vedere cosa ti viene passato. Quando il valore è "Apple", imposta enum su GreenApple o RedApple sulla base di una logica.

0

Ho cercato risposte simili anch'io e l'ho scritto per rilevare l'eccezione quando il codice XML contiene un valore per un enum non valido. Rimuove quell'elemento e prova a deserializzare di nuovo. Se l'elemento è richiesto, otterrai comunque un'eccezione. E 'imperfetta, ma dovrebbe ottenere la maggior parte del modo in cui si desidera essere

private const string XmlError = "There is an error in XML document "; 
    private const string InstanceValidationError = "Instance validation error:"; 
    private static readonly Regex XmlErrorRegex = new Regex("There is an error in XML document \\((\\d+), (\\d+)\\)."); 
    private static readonly Regex InstanceValidationErrorRegex = new Regex("Instance validation error: '(\\S+)' is not a valid value for (\\S+)."); 
    private const string TagFinderString = "\\>{0}\\</(\\S+)\\>"; 

    /// <summary> 
    /// Helper method to deserialize xml message 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="message"></param> 
    /// <returns></returns> 
    public T Deserialize(string message) 
    { 
     var result = default(T); 
     if (!string.IsNullOrEmpty(message)) 
     { 
      using (var reader = new StringReader(message)) 
      { 
       try 
       { 
        result = (T)_serializer.Deserialize(reader); 
       } 
       catch (InvalidOperationException ex) 
       { 
        if (ex.Message.StartsWith(XmlError)) 
        { 
         if(ex.InnerException != null && ex.InnerException.Message.StartsWith(InstanceValidationError)) 
         { 
          var instanceValidationErrorMatches = InstanceValidationErrorRegex.Matches(ex.InnerException.Message); 
          if (instanceValidationErrorMatches.Count > 0) 
          { 
           var locationMatches = XmlErrorRegex.Matches(ex.Message); 
           var startIndex = GetStartIndex(message, locationMatches); 
           var match = instanceValidationErrorMatches[0]; 
           if(match.Groups.Count > 0) 
           { 
            var toRemove = GetToRemove(message, match, startIndex); 

            return Deserialize(message.Replace(toRemove, string.Empty)); 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
     return result; 
    } 

    private static string GetToRemove(string message, Match match, int startIndex) 
    { 
     var value = match.Groups[1]; 
     var tagFinder = new Regex(string.Format(TagFinderString, value)); 
     var tagFinderMatches = tagFinder.Matches(message.Substring(startIndex)); 
     var tag = tagFinderMatches[0].Groups[1]; 

     return string.Format("<{0}>{1}</{0}>", tag, value); 
    } 

    private static int GetStartIndex(string message, MatchCollection locationMatches) 
    { 
     var startIndex = 0; 
     if (locationMatches.Count > 0) 
     { 
      var lineNumber = int.Parse(locationMatches[0].Groups[1].Value); 
      var charIndex = int.Parse(locationMatches[0].Groups[2].Value); 
      using (var locationFinder = new StringReader(message)) 
      { 
       for (var i = 1; i < lineNumber; i++) 
       { 
        startIndex += locationFinder.ReadLine().Length; 
       } 
      } 
      startIndex += charIndex; 
     } 
     return startIndex; 
    }