views:

315

answers:

4

I have a class with some collections in them, and I would like to serialize instances of this class to XML without having to initialize the collections to be empty, and without having to implement IXmlSerializable. I don't care if it creates empty elements, or doesn't create the elements at all. Just that it works without having to initialize a collection for each collection based property.

I have look at all the XML attributes I can decorate the properties with, and have not had any success with this. This seems like a simple thing to do that is can have an element or just none at all. Then when it is being deserialized it would just leave them null or ignore them period.

Here is a simple version of a class to use for working through this issue. Using this and the defaults you get an exception "Object reference not set to an instance of an object" due to the collections being null;

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 Thanks for the helps guys, it turns out the issue was in my GetHashCode method which didn't handle the null correctly. Once I fixed this all was good. I marked the first one to answer as being correct. Sorry for the Red Herring, but working through it with you guys did help.

+4  A: 

You do not need to initialize collections in order to serialize the class to XML. Here's a simple program to demonstrate:

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();
    }
}

This will print the following output:

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

In other words, null collection properties behave the same way as any other null property - they don't get serialized at all (unless you change the default value, which I haven't).

Aaronaught
I updated the question, I get and exception "Object reference not set to an instance of an object" when doing this. I am doing this to a file using StreamWriter and doing from a ToXmlFile method on the class itself which using "this" keyword to reference what object to serialize. The classes defined for the generic lists are simple with only primitives or enums in them. What you say is how I expect it to work, however it doesn't. I will update the class with the code used for serialization as well.
Rodney Foley
Thanks, the issue was somewhere else as Brian eluded to in his comment on the question.
Rodney Foley
A: 

You can serialize this without a problem only you have to send the types of car, home and pet when you serialize in the extraTypes parameter.

slayerIQ
A: 

You mention an exception during (de)serialization; what you have should work OK (at least, according to how you define the question). I wonder if you actually have:

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; }
}

(not uncommon to not want a public setter)

Well, XmlSerializer is fussy about this; you either need a public setter, or (as somebody pointed out recently) no setter; for example:

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; } }
}
Marc Gravell
A: 

I think setting the return type of the XMLSerialisation method to a bool would allow you to handle errors in a safer fashion as opposed to the current method:

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;
}

Which can then be used like so:

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

This is merely a crude example however i have used a similar method in my own applications when loading or saving data and it works well, also a good visual indicator for the end user.

Jamie Keeling