XmlSerializer and CollectionBase
I just want to share some things that I have learned while fighting with getting an XML fragment to deserialize into a CollectionBase derived object. What a nightmare!
The XML fragment is similar to the following:
<items> <item name='name1' uri='uri1'/> <item name='name2' uri='uri2'/> </items>
I first start off with the way that every other class works:
[XmlRoot("items")] public class ItemCollection : CollectionBase { ... Complete implementation of a typed collection ... ... including typed Add method and indexer ... } [XmlRoot("item")] public class Item { ... Implementation of Item properties ... }
This gives the very cryptic error along the lines of there was an error reflecting ItemCollection. Finally, after some digging, I come across the real cause of the error. XML attributes are not allowed on the type ItemCollection. Why would that be the case? Who knows?
No problem, I think as I remove the XmlRoot attribute from ItemCollection. At this point, Im no longer receiving errors. However, none of my items are being deserialized. Argh!
So, finally I discover the XmlArray and XmlArrayItem elements, which seem to do the trick. The drawback is that I have to have a container class, as these attributes can’t be applied to a class. Not necessarily my first choice, but, I suppose it will do.
Final chunk of code:
public class DataContainer { [XmlArray("items")] [XmlArrayItem("item", typeof(Item))] public ItemCollection Items { get { return _items; } set { _items = value; } } }
All in all, I dont see why the serialization of collections is so different for collections as opposed to other classes.
Hi Matt,
I have a further more frustrating example. What do you do if the array list itself has an attribute?
<CHARGES COUNT=”0003″>
<CHARGE ITEMNUMBER=”31730000002004″ />
<CHARGE ITEMNUMBER=”31730009761045″ />
<CHARGE ITEMNUMBER=”31730009761055″ />
</CHARGES>
In this case, I think you’re going to have to implement IXmlSerializable yourself.
See http://www.mattberther.com/2004/06/000487.html for an example.
I had the same problem an I solved it in the same way. Things become real tricky if you want to do the following
1. Inherit Item class
2. Enable XML serialization for all classes that are derived from Item class and added to collection
Parcial solution is to use XmlItemType attributes and to specify classes that can be added to ItemCollection. That approach is ok if you have final number of derived classes and all those classes are under you contol.
The real problem is if you want to enable some kind of plug-in mechanism for other developert to extend Item Class, edit xml file and deserailize objects. In that case some developer can implement public class TrickyItem : Item that can be added to ItemCollection, serialized and deserialized but as we bo not know about TrickyItem in coding time, we were unable to add corresponding XmlItemType attribute for TrickyItem. When we add TrickzItem in colection and try to serialize it run-time exception will occur.
Does anyone have some idea how to avoid it?
Yeah, I know how to solve it. You need to Serialize the unknown Types names into a string array aswell using the 2nd XmlSerializer ctr (Type baseType, Type[] extraTypes).
This way when you Deserialize back again, 1st you retrieve your array of extra Types and voila you have your object back.
Trick is to know the extra Types that your serialized class references, I wrote a TypeReferenceBuilder class which iterates the instance before Serializing to retrieve this at runtime.
Cheers
I think there may be an issue with the CustomCollection object (the one that implements CollectionBase)
I think you MUST have an indexer on the CustomCollection object.
See code snipplet below. I may try to post a sample.
I’ve been pee’ing around with this all day, and finally
got a CollectionBase object to serialize.
public MyCustomObject this[ int index ]
{
get
{
return ( MyCustomObject )base.List[index];
}
}
PS
The other thing which took me a while to figure out… what the Xml tags on the properties. I finally got it to work with….
Notice that there are 2 xml attribute tags on 1 line.
//private CustomCollection m_custcoll= new CustomCollection();
[ XmlArray("Itemssssssss"), XmlArrayItem(typeof(CustomObject)) ]
public CustomCollection thisIsAProperty
{
get { return m_custcoll; }
set { m_custcoll = value; }
}
http://spaces.msn.com/members/sholliday/
9/21/2005 blog entry
I added some code samples and what I found. I agree with Matt about it, and my posting(s) above really don’t disprove anything he has said.
Brilliant, thank you so much. Been trying to solve this problem for awhile now.


