2009-12-28 5 views
2

J'ai un objet qui est sérialisé/désérialisé via XmlSerializer en C#, .NET 3.5. Une des propriétés (et plus dans le futur) est une collection: Liste où T est une valeur enum. Cela sérialise/désérialise l'amende.C# Désérialisation XML avec valeurs par défaut

Nous utilisons également un mécanisme de "valeurs par défaut" pour fournir des valeurs par défaut pour l'objet, dans le cas où la version sérialisée n'a pas de valeur définie. comme un exemple simple, voici ce que nous sommes dong:

public enum MyEnum { 
    Value1, 
    Value2 
} 

public class Foo 
{ 

    public List SomeSetting{ get; set; } 

    public Foo() 
    { 
    SomeSetting = new List(); 
    SomeSetting.Add(MyEnum.Value1); 
    SomeSetting.Add(MyEnum.Value2); 
    } 
} 

Ce code fonctionne très bien pour définir les valeurs par défaut de SomeSetting lorsque l'objet est construit. Cependant, lorsque nous désérialisons un fichier xml avec des valeurs pour SomeSetting, cette configuration par défaut cause des problèmes: le deserializer xml ne réinitialise pas la collection SomeSetting - il ne l'efface pas et le remplit avec de nouvelles données . Au contraire, il ajoute aux données qui sont déjà là. Donc, si le fichier xml contient la valeur sérialisée 1, quand je désérialise ce fichier, je finis par SomeSettings ayant comme valeurs les valeurs {Value1, Value2, Value1}.

J'ai besoin d'un moyen pour que le processus de désérialisation xml permette l'existence de mes valeurs par défaut lorsqu'il n'y a pas de données pour SomeSetting dans le document xml, et aussi pour remplacer les valeurs SomeSetting lorsqu'il y a des données dans le document xml. Comment puis-je faire ceci?

FYI - ce n'est pas la seule propriété dans le document. Le document existe et est en cours de sérialisation/désérialisation pour les autres valeurs «simples». C'est la propriété qui cause des problèmes, cependant. Je dois soutenir ce scénario parce que je dois le faire beaucoup maintenant.

+0

Je pense que l'interface IXmlSerializable me ce que je veux ... Quelqu'un at-il une suggestion pour savoir comment utiliser cette interface pour résoudre mon problème? –

+0

Une autre option pourrait être au lieu de vous-même l'analyse syntaxique http://stackoverflow.com/questions/14768052/c-sharp-xml-deserialize-plus-design-suggestions – surya

Répondre

1

FYI - J'ai résolu ceci avec l'interface IXMLSerializable. Notez que ce code est très spécifique à mes besoins dans cette classe, donc YMMV.



     public void WriteXml(XmlWriter writer) 
     { 
      foreach (PropertyInfo prop in GetType().GetProperties()) 
      { 
       XmlIgnoreAttribute attr; 
       if (prop.TryGetAttribute(out attr)) 
        continue; 

       if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(List))) 
       { 
        XmlSerializer serializer = new XmlSerializer(prop.PropertyType, new XmlRootAttribute(prop.Name)); 
        serializer.Serialize(writer, prop.GetValue(this, null)); 
       } 
       else 
       { 
        writer.WriteElementString(prop.Name, prop.GetValue(this, null).ToString()); 
       } 
      } 
     } 

     public void ReadXml(XmlReader reader) 
     { 
      if (reader.IsEmptyElement) 
       return; 

      XmlDocument xDoc = new XmlDocument(); 
      xDoc.Load(reader); 

      Type type = GetType(); 

      foreach (XmlNode node in xDoc.DocumentElement.ChildNodes) 
      { 
       PropertyInfo prop = type.GetProperty(node.Name); 
       if (prop != null && prop.CanWrite) 
       { 
        object value; 
        if (prop.PropertyType.IsEnum) 
        { 
         string stringValue = node.InnerText; 
         value = Enum.Parse(prop.PropertyType, stringValue); 
        } 
        else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(List))) 
        { 
         Type enumType = prop.PropertyType.GetGenericArguments()[0]; 
         value = Activator.CreateInstance(prop.PropertyType); 
         var addMethod = value.GetType().GetMethod("Add"); 
         foreach (XmlNode subNode in node.ChildNodes) 
         { 
          object enumValue = Enum.Parse(enumType, subNode.InnerText); 
          addMethod.Invoke(value, new[] { enumValue }); 
         } 
        } 
        else 
        { 
         string stringValue = node.InnerText; 
         value = Convert.ChangeType(stringValue, prop.PropertyType); 
        } 
        prop.SetValue(this, value, null); 
       } 
      } 
     } 

     public XmlSchema GetSchema() 
     { 
      return null; 
     } 
0

Rapide et sale est à mettre en œuvre ISupportInitialize. Tous les sérialiseurs .NET (IIRC) respectent cette interface et appellent EndInit après désérialisation.

Vous pouvez vérifier le contenu de votre collection à ce stade et déterminer si vous devez ajouter les valeurs par défaut à ce moment-là. Je suggère également de vérifier si votre instance a été initialisée avant la première utilisation et de lancer une exception si ce n'est pas le cas. Cela garantira que les autres utilisateurs de votre classe sauront que votre instance doit être initialisée avant utilisation.

+0

ne semble pas fonctionner ... les méthodes de cette interface ne sont pas appelés par le sérialiseur xml. –