2010-01-26 7 views
5

J'ai une classe avec quelques collections, et je voudrais sérialiser les instances de cette classe en XML sans avoir à initialiser les collections pour être vides, et sans avoir à implémenter IXmlSerializable. Je m'en fiche si cela crée des éléments vides, ou ne crée pas les éléments du tout. Juste que cela fonctionne sans avoir à initialiser une collection pour chaque propriété basée sur la collection.Sérialisation XML .NET et collections nulles

J'ai regardé tous les attributs XML que je peux décorer les propriétés, et je n'ai pas eu de succès avec ça. Cela semble être une chose simple à faire qui peut avoir un élément ou tout simplement aucun. Ensuite, quand il est désérialisé, il les laisse simplement nuls ou les ignore.

Voici une version simple d'une classe à utiliser pour résoudre ce problème. En utilisant ceci et les valeurs par défaut, vous obtenez une exception "Référence d'objet non définie sur une instance d'un objet" en raison de la nullité des collections;

public class MyClass 
{ 
    public string Name { get; set; } 
    public bool IsAlive { get; set; } 
    public List<Car> Cars { get; set; } 
    public List<Home> Homes { get; set; } 
    public List<Pet> Pets { get; set; } 

    public void ToXmlFile(string fileName) 
    { 
     XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); 
     TextWriter writer = new StreamWriter(fileName); 
     serializer.Serialize(writer, this); 
     writer.Close(); 
    } 
} 

EDIT Merci pour l'aide les gars, il se trouve la question était dans ma méthode GetHashCode qui ne gère pas correctement la valeur nulle. Une fois que j'ai réparé tout cela était bon. J'ai marqué le premier à répondre comme étant correct. Désolé pour le Red Herring, mais en travaillant avec vous les gars ont aidé.

+0

Et quel est le problème? Cela devrait fonctionner (sérialiser et désérialiser au moins); quel comportement est-ce que vous n'aimez pas? –

+0

Je n'ai pas pu reproduire l'exception que vous prétendez obtenir. J'ai été en mesure de sérialiser et de désérialiser une instance de votre MyClass exacte comme vous l'avez donné. Peut-être qu'il se passe quelque chose d'autre? –

+0

@Brian ouais quelque chose d'autre se passait, merci pour toute l'aide rapide et montrant que ce n'était pas le code XML lui-même. :) –

Répondre

5

Vous n'avez pas besoin d'initialiser les collections pour sérialiser la classe en XML. Voici un programme simple à démontrer:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyClass c = new MyClass() { Name = "Test", IsAlive = true }; 
     XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      serializer.Serialize(ms, c); 
      Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray())); 
     } 
     Console.ReadLine(); 
    } 
} 

Cette imprimera la sortie suivante:

<?xml version="1.0"?> 
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Name>Test</Name> 
    <IsAlive>true</IsAlive> 
</MyClass> 

En d'autres termes, null propriétés de collection se comportent de la même manière que tout autre null bien - ils ne reçoivent pas sérialisé du tout (sauf si vous changez la valeur par défaut, ce que je n'ai pas).

+0

J'ai mis à jour la question, je reçois et l'exception "Référence d'objet n'est pas définie à une instance d'un objet" en faisant cela. Je fais cela dans un fichier en utilisant StreamWriter et en faisant à partir d'une méthode ToXmlFile sur la classe elle-même qui utilise le mot-clé "this" pour référencer l'objet à sérialiser. Les classes définies pour les listes génériques sont simples avec uniquement des primitives ou des énumérations. Ce que vous dites est comment je m'attends à ce que cela fonctionne, mais ce n'est pas le cas. Je mettrai à jour la classe avec le code utilisé pour la sérialisation. –

+0

Merci, la question était ailleurs comme Brian a éludé dans son commentaire sur la question. –

0

Vous pouvez sérialiser cela sans problème, vous devez seulement envoyer les types de voiture, de maison et d'animal familier lorsque vous sérialisez dans le paramètre extraTypes.

0

Vous mentionnez une exception lors de la (dé) sérialisation; ce que vous avez devrait fonctionner correctement (au moins, selon la façon dont vous définissez la question).Je me demande si vous avez réellement:

public class MyClass 
{ 
    public string Name { get; set; } 
    public bool IsAlive { get; set; } 
    public List<Car> Cars { get; private set; } 
    public List<Home> Homes { get; private set; } 
    public List<Pet> Pets { get; private set; } 
} 

(pas rare de ne pas vouloir un setter public)

Eh bien, XmlSerializer est pointilleux à ce sujet; soit vous avez besoin d'un setter public, ou (comme quelqu'un l'a fait remarquer récemment) no setter; par exemple:

public class MyClass 
{ 
    public string Name { get; set; } 
    public bool IsAlive { get; set; } 
    private readonly List<Car> cars = new List<Car>(); 
    public List<Car> Cars { get { return cars; } } 
    private readonly List<Home> homes = new List<Home>(); 
    public List<Home> Homes { get { return homes; } } 
    private readonly List<Pet> pets = new List<Pet>(); 
    public List<Pet> Pets { get { return pets; } } 
} 
0

Je pense que la définition du type de retour de la méthode de XMLSerialisation à un bool vous permettrait de gérer les erreurs d'une façon plus sûre, par opposition à la méthode actuelle:

public bool ToXmlFile(string fileName) 
{ 
    if(fileName != "") 
    { 
     XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); 
     TextWriter writer = new StreamWriter(fileName); 
     serializer.Serialize(writer, this); 
     writer.Close(); 
     return true; 
    } 
    return false; 
} 

qui peut ensuite être utilisé comme ceci:

if(ToXMLFile) 
{ 
    MessageBox.Show("Save Succesful"); 
} 
else 
(
    MessageBox.Show("Save unsuccesful"); 
) 

Ceci est simplement un exemple brut mais j'ai utilisé une méthode similaire dans mes propres applications lorsque loa ding ou d'enregistrer des données et cela fonctionne bien, également un bon indicateur visuel pour l'utilisateur final.