Scott Hanselman

XmlSerializing a Generic List<>

April 17, '07 Comments [10] Posted in Programming | XmlSerializer
Sponsored By

There's lots of good techniques out there for using the XmlSerializer to serialize a Generic List<> type. You can implement IXmlSerializable and some other trickiness.

Here's the simplest possible thing I could do to make it work while working on a hobby project over lunch today with a friend.

UPDATE: I'm a dork and didn't see the forest for the trees on this one. I don't need a parallel array at all. That's my old 1.1 brain creeping in. Thanks to folks in the comments. It works fine just like this. I'm not sure why I thought it didn't work when I tried it before. Thanks folks!

namespace Poo
{
    public class Foo
    {
        public Foo() { FooReadings = new List(); }

        [XmlArray("FooReadings")] //Even this attribute isn't really needed if you accept the default.
public List<FooReading> FooReadings; } public class FooReading { public FooReading() { } public FooReading(DateTime date, decimal thing2) { this.Thing2 = thing2; this.Date = date; } public decimal Thing2; public DateTime Date; } }

The technique below is useful for other things, but not in this instance.

namespace Poo
{
    public class Foo
    {
        public Foo() { FooReadings = new List(); }

        [XmlIgnore]
        public List<FooReading> FooReadings;

        [XmlArray("FooReadings")]
        public FooReading[] ArrayFooReadings
        {
            get { return FooReadings.ToArray(); }
            set { FooReadings = new List(value); }
        }
    }

    public class FooReading
    {
        public FooReading() { }

        public FooReading(DateTime date, decimal thing2)
        {
            this.Thing2 = thing2;
            this.Date = date;
        }

        public decimal Thing2;
        public DateTime Date;
    }
}

The "Real List<>" is ignored and the "fake" one is presented as an Array in the Getters/Setter. Not pretty, to be sure.

What better ways are there that you prefer?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Tuesday, 17 April 2007 12:19:52 UTC
Scott, I'm 99% sure that you can serialize a generic List exactly how it is - what situations have you run into where you can't?
Tuesday, 17 April 2007 12:21:42 UTC
Scott, I'm 99% sure that you can serialize a generic List exactly how it is - what situations have you run into where you can't?
Tuesday, 17 April 2007 13:12:30 UTC
I agree with Paul. I'm serializing to and from generic Lists without any magic. The only problem is that if you serialize an object with a generic List member set to null, when you deserialize, the member will contain an instantiated but empty generic List instead. Can be tricky when trying to conform to strict XSDs defined by a third party.
Jason
Tuesday, 17 April 2007 14:29:27 UTC
In my experience, there are three ways that you can use the Xml Serializer:

1) Leave things as is and let the Xml Serializer do things automagically for you (make sure you have getters and setters for all public properties... making your object simply a value object). Note: Only default constructors are used.

2) Implement the XmlIgnoreAttribute, XmlElementAttribute, XmlAttributeAttribute attributes and all the others in this group (as you have done here). Note (again): Only default constructors are used.

3) Explicitly implement the IXmlSerializable interface (use when you want a higher degree of control over the schema but can generally be avoided) where you implement the ReadXml and WriteXml methods (the GetSchema method can generally be left returning null).

In this case (3), you will likely want to test to ensure that your serialization and deserialization works as expected for optional elements, values, etc.

I have done this in the past like this:

Unit testing classes for serialization using the XmlSerializer: http://huntjason.spaces.live.com/blog/cns!9D2E96F2AA6AE85F!401.entry

(sorry, I am not certain how to make links in DasBlog comments).

Hope this helps,
Jason Hunt
Tuesday, 17 April 2007 16:26:42 UTC
As long as the elements in the generic list is marked serializable you can serialize out-of-the-box.
Tuesday, 17 April 2007 17:15:52 UTC
Like others have said, this is much simpler than you're making it out to be:

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

namespace SerializeList
{
class Program
{
static void Main(string[] args)
{
Foo f = new Foo();
f.FooReadings.Add(new FooReading(DateTime.Now, 1));
f.FooReadings.Add(new FooReading(DateTime.MinValue, 2));
XmlSerializer xs = new XmlSerializer(typeof(Foo));
using (StreamWriter writer = new StreamWriter(@"c:\foo.xml"))
{
xs.Serialize(writer, f);
}
// Check your C drive for a beautious XML document
}
}

public class Foo
{
public Foo() { fooReadings = new List<FooReading>(); }

private List<FooReading> fooReadings;
public List<FooReading> FooReadings
{
get { return fooReadings; }
set { fooReadings = value; }
}
}

public class FooReading
{
public FooReading() { }

public FooReading(DateTime date, decimal thing2)
{
this.Thing2 = thing2;
this.Date = date;
}

public decimal Thing2;
public DateTime Date;
}
}
Tuesday, 17 April 2007 17:39:03 UTC
Thanks guys, you're totally right. I don't know why this "didn't work" the first time I tried it. I think I just brain-farted and missed something obvious. I tried again and it totally worked. Post updated.
Tuesday, 17 April 2007 18:17:56 UTC
Ah I see - Scott, we use this list to filter our developer interview candidates - (it's amazing how many times people interview for singing jobs without asking for people to actually sing eh?):

http://www.hanselman.com/blog/WhatGreatNETDevelopersOughtToKnowMoreNETInterviewQuestions.aspx

Check out the 'Senior Developers/Architects' section for serialization questions.

>;-)
Alex B
Tuesday, 17 April 2007 18:34:00 UTC
Alex B - That's just mean, man! ;)
Wednesday, 18 April 2007 18:02:41 UTC
I have run into the same problem were I didn't work for me. If my memory serves me well, I think the issue was that I was using IList<t>.

So the following does not work.
public class Foo
{
public Foo() { FooReadings = new List(); }

[XmlArray("FooReadings")]
public IList<FooReading> FooReadings;//note that FooReadings is an IList not a List
}

Barry H.

>Thanks guys, you're totally right. I don't know why this "didn't work" the first time I tried it.
BarryH
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.