views:

1114

answers:

3

I've got a simple class that inherits from Collection and adds a couple of properties. I need to serialize this class to XML, but the XMLSerializer ignores my additional properties.

I assume this is because of the special treatment that XMLSerializer gives ICollection and IEnumerable objects. What's the best way around this?

Here's some sample code:

using System.Collections.ObjectModel;
using System.IO;
using System.Xml.Serialization;

namespace SerialiseCollection
{
    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyCollection();
            c.Add("Hello");
            c.Add("Goodbye");

            var serializer = new XmlSerializer(typeof(MyCollection));
            using (var writer = new StreamWriter("test.xml"))
                serializer.Serialize(writer, c);
        }
    }

    [XmlRoot("MyCollection")]
    public class MyCollection : Collection<string>
    {
        [XmlAttribute()]
        public string MyAttribute { get; set; }

        public MyCollection()
        {
            this.MyAttribute = "SerializeThis";
        }
    }
}

This outputs the following XML (note MyAttribute is missing in the MyCollection element):

<?xml version="1.0" encoding="utf-8"?>
<MyCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
    <string>Hello</string>
    <string>Goodbye</string>
</MyCollection>

What I want is

<MyCollection MyAttribute="SerializeThis" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
    <string>Hello</string>
    <string>Goodbye</string>
</MyCollection>

Any ideas? The simpler the better. Thanks.

+5  A: 

Collections generally don't make good places for extra properties. Both during serialization and in data-binding, they will be ignored if the item looks like a collection (IList, IEnumerable, etc - depending on the scenario).

If it was me, I would encapsulate the collection - i.e.

[Serializable]
public class MyCollectionWrapper {
    [XmlAttribute]
    public string SomeProp {get;set;} // custom props etc
    [XmlAttribute]
    public int SomeOtherProp {get;set;} // custom props etc
    public Collection<string> Items {get;set;} // the items
}

The other option is to implement IXmlSerializable (quite a lot of work), but that still won't work for data-binding etc. Basically, this isn't the expected usage.

Marc Gravell
A: 

I've been fighting with the same issue Romaroo is (wanting to add properties to the xml serialization of a class that implements ICollection). I have not found any way to expose properties that are in the collection class. I even tried using the XmlAttribute tag and making my properties show up as attributes of the root node, but no luck there either. I was however able to use the XmlRoot tag on my class to rename it from "ArrayOf...". Here are some references in case you're interested:

VanOrman
+1  A: 

If you do encapsulate, as Marc Gravell suggests, the beginning of this post explains how to get your XML to look exactly like you describe.

http://blogs.msdn.com/youssefm/archive/2009/06/12/customizing-the-xml-for-collections-with-xmlserializer-and-datacontractserializer.aspx

That is, instead of this:

<MyCollection MyAttribute="SerializeThis" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <Items>
    <string>Hello</string>
    <string>Goodbye</string>
  <Items>
</MyCollection>

You can have this:

<MyCollection MyAttribute="SerializeThis" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;      
  <string>Hello</string>
  <string>Goodbye</string>
</MyCollection>
Neil Whitaker
@neilwhitaker1: I upvoted this answer, but it would be even better if you described the technique in the answer rather than making us go read the blog post. You can still reference the post.
John Saunders