By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,958 Members | 1,179 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,958 IT Pros & Developers. It's quick & easy.

XmlSerializer and public ArrayList properties

P: n/a
Before I continue, I'm going to begin by saying I'm not by any means
an expert- I've been using .NET with C# for about 4 months now, and
basically just learning by example and docs.

A game project I work on uses Xml serialization to store game objects
for loading. One of the techniques we use is to make an array
property and use the set block to perform actions on the values after
they're loaded from the xml, as in:

public string[] Ids
{
set
{
foreach(string id in value) this.AddId(id);
}
get { return null}
}

Well, I had set about wanting some type independance and thought I
would use an ArrayList for a different such task. But when I set
about making a similar property of type ArrayList, I found that it
wasn't working at all. Set would get called, but the value was always
empty. (value.Count==0).

There IS a document on MSDN that describes the serialization of
ArrayLists. At first, therefore, I believed I was using the wrong
attributes and that the xml reader was ignoring what it thought was
unused elements.

http://msdn.microsoft.com/library/de...attributes.asp

While MSDN says that to serialize an ArrayList you should use the
[XmlElement] attribute, this is misleading in the document because it
creates a flat array- no <ArrayListName>(contents)</ArrayListName>,
just a sequence of named elements.

Instead, use the attributes that are also used for arrays.
[XmlArray("NameOfArrayElement")] and one or more
[XmlArrayItem("NameOfType", typeof(YourType)]. The document describes
these, and they work just fine for ArrayLists too.

I googled for MANY hours reading everything I could find on the
XmlSerializer and properties and arraylists-- so far I've not found
anywhere that lists what I found.

For Arrays, the XmlSerializer creates the array, fills it internally,
and then calls set() on the property with the filled array.

For ArrayLists, it uses a much more convoluted method:

1) The serializer calls get() to find out if the ArrayList is null or
not.

2) If and ONLY IF it is null, it then calls set() with a new, empty
ArrayList. This is the only time set() EVER MIGHT be called.

3) For every object deserialized from the xml, the serializer calls
get()- expecting a real, persisted arraylist to be returned- and uses
Add() on the result to add the object. If your get() returns a Clone
of the arraylist, it will never actually fill.

What does this mean? You CANNOT use a property to accept input from
an xml file without saving the result- the ArrayList MUST exist in a
field somewhere and MUST be returned by the get() property and setable
by the set() property.

Also, set() is NEVER called on the completely deserialized ArrayList-
only on empty new ones, if necessary. Therefore, you must use the
IDeserializationCallback interface and implement OnDeserialization()
to act on the contents of the filled arraylist after loading.
Having figured all this out, I THEN ran into a hurdle for one very
infrequently mentioned fact: IDeserializationCallback applies only to
the BinaryFormatter, NOT the XmlSerializer. Therefore, in your
applications loading method, you may find it to your advantage to
define your own IXmlDeserializationCallback interface and check for
it when an object is loaded.

The disadvantage to this method is that because the XmlSerializer is
not doing the actual calling, internal objects (fields, properties)
which implement this interface will NOT have the method invoked.
Therefore, in your implementation of OnXmlDeserialization(), you
should call ONXmlDeserialization for your fields that implement
IXmlDeserializationCallback.

I hope this helps somebody- this is my first post writing like I know
what I'm talking about! ;) I'll feel like quite the fool if everyone
already knew about this and I was the only one in the dark...)

--------------------------------
From: Jamus Sprinson
jamuspsi at earthlink dot net
Nov 12 '05 #1
Share this Question
Share on Google+
1 Reply


P: n/a
Thank you.

The behavior you have described for XML de-serializing ArrayLists makes
sense. think about the concepts - in general, whether you are talking about
xml de-serialization or not, the arraylist doesn't get destroyed and
re-created every time a caller adds an item to it; Instead, the usage
pattern for an arraylist is to create it (or set it, as you say), and then
add and remove items to it.

It is a typical design when exposing a property from a type to have a hidden
field that lies behind the property. The degernerate case is

public class Foo {
private ArrayList list;
public ArrayList List {
get { return list;}
set {list=value; }
}
}
"Jamus Sprinson" <ja******@earthlink.net> wrote in message
news:dc**************************@posting.google.c om...
Before I continue, I'm going to begin by saying I'm not by any means
an expert- I've been using .NET with C# for about 4 months now, and
basically just learning by example and docs.

A game project I work on uses Xml serialization to store game objects
for loading. One of the techniques we use is to make an array
property and use the set block to perform actions on the values after
they're loaded from the xml, as in:

public string[] Ids
{
set
{
foreach(string id in value) this.AddId(id);
}
get { return null}
}

Well, I had set about wanting some type independance and thought I
would use an ArrayList for a different such task. But when I set
about making a similar property of type ArrayList, I found that it
wasn't working at all. Set would get called, but the value was always
empty. (value.Count==0).

There IS a document on MSDN that describes the serialization of
ArrayLists. At first, therefore, I believed I was using the wrong
attributes and that the xml reader was ignoring what it thought was
unused elements.

http://msdn.microsoft.com/library/de...attributes.asp

While MSDN says that to serialize an ArrayList you should use the
[XmlElement] attribute, this is misleading in the document because it
creates a flat array- no <ArrayListName>(contents)</ArrayListName>,
just a sequence of named elements.

Instead, use the attributes that are also used for arrays.
[XmlArray("NameOfArrayElement")] and one or more
[XmlArrayItem("NameOfType", typeof(YourType)]. The document describes
these, and they work just fine for ArrayLists too.

I googled for MANY hours reading everything I could find on the
XmlSerializer and properties and arraylists-- so far I've not found
anywhere that lists what I found.

For Arrays, the XmlSerializer creates the array, fills it internally,
and then calls set() on the property with the filled array.

For ArrayLists, it uses a much more convoluted method:

1) The serializer calls get() to find out if the ArrayList is null or
not.

2) If and ONLY IF it is null, it then calls set() with a new, empty
ArrayList. This is the only time set() EVER MIGHT be called.

3) For every object deserialized from the xml, the serializer calls
get()- expecting a real, persisted arraylist to be returned- and uses
Add() on the result to add the object. If your get() returns a Clone
of the arraylist, it will never actually fill.

What does this mean? You CANNOT use a property to accept input from
an xml file without saving the result- the ArrayList MUST exist in a
field somewhere and MUST be returned by the get() property and setable
by the set() property.

Also, set() is NEVER called on the completely deserialized ArrayList-
only on empty new ones, if necessary. Therefore, you must use the
IDeserializationCallback interface and implement OnDeserialization()
to act on the contents of the filled arraylist after loading.
Having figured all this out, I THEN ran into a hurdle for one very
infrequently mentioned fact: IDeserializationCallback applies only to
the BinaryFormatter, NOT the XmlSerializer. Therefore, in your
applications loading method, you may find it to your advantage to
define your own IXmlDeserializationCallback interface and check for
it when an object is loaded.

The disadvantage to this method is that because the XmlSerializer is
not doing the actual calling, internal objects (fields, properties)
which implement this interface will NOT have the method invoked.
Therefore, in your implementation of OnXmlDeserialization(), you
should call ONXmlDeserialization for your fields that implement
IXmlDeserializationCallback.

I hope this helps somebody- this is my first post writing like I know
what I'm talking about! ;) I'll feel like quite the fool if everyone
already knew about this and I was the only one in the dark...)

--------------------------------
From: Jamus Sprinson
jamuspsi at earthlink dot net

Nov 12 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.