2009-05-23

Serialize generics list part 1

This post is the second of series on serialization in WCF (previous post).

The topic of this post is dealing with writing data contract that inherit from type that does not decorated with the DataContract attribute (in our case List<T>).

Downloads available here

Why shouldn’t it work?

consider the following type declaration:

[DataContract]
public class ListCustom: List<CompositeType> {…}

The above code will not pass the data contract serialization because List<T> does not decorated with DataContract attribute

What can we do about it?

We can certainly refactor the class to composite pattern which will look like the following:

[DataContract]
public class ListCustom{
private List<CompositeType> m_aItems =
new List<CompositeType> ();

[DataMember]
private CompositeType[] Values {
get {
if (m_aItems == null)
m_aItems = new List<CompositeType> ();
return m_aItems.ToArray ();
}
set {
if (m_aItems == null)
m_aItems = new List<CompositeType> ();
m_aItems.AddRange (value);
}
}
}

This is simple work around but we have to refactor the code and lose the inheritance benefits.

Can we serialize none decorated types?

The answer is yes, and this is how we do it.

It is not the simplest task if you don’t familiar with xml serialization, but I will try to explain it.

Data contract serialization do know to serialize types that implement xml serialization, so it give us the option to instruct the serializer how to serialize the base type which is not decorated with DataContract attribute.

Please read the code and I will explain it latter:

[XmlRoot (Namespace = "http://...")]
public class ListCustom: List<CompositeType>, IXmlSerializable {
XmlSchema IXmlSerializable.GetSchema () {
throw new NotImplementedException ();
}
void IXmlSerializable.ReadXml ( XmlReader reader ) {
var ser = new DataContractSerializer (typeof (CompositeType));
...
while (reader.Name == "CompositeType") {
var item = ser.ReadObject (reader) as CompositeType;
this.Add (item);
}
}

void IXmlSerializable.WriteXml ( XmlWriter writer ) {
var ser = new DataContractSerializer (typeof (CompositeType));

writer.WriteStartElement ("Items", "http://...");
foreach (var item in this) {
ser.WriteObject (writer, item);
}
writer.WriteEndElement ();
}
}

What’s in the code?

  • Instead of decorating the class with DataContract attribute we decorating it with XmlRoot attribute.
  • We implementing IXmlSerializable so we can customize the serialization processing
  • You can ignore GetSchema
  • The serialization process is using ReadXml for deserialization and WriteXml for serialization.
    you can just copy and paste the code pattern all it’s doing is using XmlReader and XmlWriter combine with DataContractSerializer in order to inject or fetch the list item to or from the xml stream.

Summary

We saw that we can keep our functionality in term of inheritance of none serializable type and still serialize it with data contract serialization.

Downloads available here

Part 2 will take it one step further and use

class ListCustom<T>: List<T>

Following Posts

Previous Posts

No comments: