When using XML serialization on a class type that contains array like (array, collection, list, etc) properties, the de-serialization result could be inconsistent for an array type property comparing to a collection type property.
First of all, the following type “Foo” contains an int array private field and its encapsulating property:
public class Foo
{
private int[] _bars;
public int[] Bars
{
get
{
if (_bars == null)
_bars = new int[] { 0 };
return _bars;
}
set { _bars = value; }
}
}
When doing a round trip of XML serialization of an instance of the “Foo” type:
static void TFoo()
{
string xml = string.Empty;
XmlSerializer xs = new XmlSerializer(typeof(Foo));
using (StringWriter sw = new StringWriter())
{
Foo foo = new Foo();
foo.Bars = new int[] { 1, 2, 3 };
xs.Serialize(sw, foo);
xml = sw.ToString();
Console.WriteLine(sw.ToString());
}
using (StringReader sr = new StringReader(xml))
{
Foo foo = xs.Deserialize(sr) as Foo;
foreach (int bar in foo.Bars)
{
Console.WriteLine(bar);
}
}
}
You get what you expect:

Now let’s try with a “Foo2” type that contains a collection of int field and its encapsulating property:
public class Foo2
{
private Collection<int> _bars;
public Collection<int> Bars
{
get
{
if (_bars == null)
{
_bars = new Collection<int>();
_bars.Add(0);
}
return _bars;
}
set { _bars = value; }
}
}
When doing a round trip of XML serialization of an instance of the “Foo2” type:
static void TFoo2()
{
string xml = string.Empty;
XmlSerializer xs = new XmlSerializer(typeof(Foo2));
using (StringWriter sw = new StringWriter())
{
Foo2 foo = new Foo2();
foo.Bars = new Collection<int>(new int[] { 1, 2, 3 });
xs.Serialize(sw, foo);
xml = sw.ToString();
Console.WriteLine(sw.ToString());
}
using (StringReader sr = new StringReader(xml))
{
Foo2 foo = xs.Deserialize(sr) as Foo2;
foreach (int bar in foo.Bars)
{
Console.WriteLine(bar);
}
}
}
You get what you do NOT expect:

In fact, disassembling the code from the xml serialization generated assembly shows that:
When the type of the property is collection, during de-serialization, an instance of the type “Foo” is constructed, followed by the “getter” of the collecton property is called, and finally all the elements in the xml are ADDed back to the collection property. Because it uses ADD, so any existing objects inside the collection property are kept untouched.
a_0_0.Add(System.Xml.XmlConvert.ToInt32(Reader.ReadElementString()));
In contrast, when the type of the property is array, the “indexer” is used to assign the element back to the array property.
a_0_0 = (global::System.Int32[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Int32));
a_0_0[ca_0_0++] = System.Xml.XmlConvert.ToInt32(Reader.ReadElementString());
In summary, instantiating a field inside its encapsulating property is commonly used, if the type is array like but not array (colleciton, enumerable, etc), you need to watch out for this xml serialization inconsistency.