Using generics to easy the pain of (xml) serialization

Published Wed, Nov 22 2006 1:55 PM

Sometimes it happens (especially when writing application frameworks) that you need to write a piece of code that needs to perform something as generically as possible. Being the OO guys that we are we tend to work a lot with polymorphism to accomplish this. Unfortunatly, polymorphism and xml serialization don't nescessarilly go hand-in-hand that well.

Say for instance that you have a class called Response which has has a derived class called DerivedResponse1:

public class Response
{
}
public class DerivedResponse1 : Response
{
}

Nothing fancy here. The code to serialize this DerivedResponse1 class would be something like the following:

void SerializeResponse(Response response)
{
    using (MemoryStream ms = new MemoryStream())
    {
        XmlSerializer ser = new XmlSerializer(typeof(Response));
        ser.Serialize(ms, response);
    }
}

Unfortunatly this doesn't work because the XML serializer complains about an error in the XML document (look at the InnerException to find out what the real error message is, which in this case is "The type DerivedResponse1 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.")

To fix this you need to exactly what the error message sais and that is to add the XmlInclude attribute to the base type like this:

[XmlInclude(typeof(DerivedResponse1))]
public abstract class Response
{
}

Ok, now comes the part where you have 70 classes deriving from Response like I did... it would be very annoying to have to attach each and every class using the XmlInclude attribute. This was kind of the problem that I had.

What I did was create a generic 'helper' class that I used as a container for the Response object. The class looks very simple kind of like this:

public class SerializationContainer<T> where T : Response
{
    private MemoryStream ms = new MemoryStream();
    
    public T Instance;
    
    public SerializationContainer(T instance)
    {
        Instance = instance;
    }
    
    public void Serialize()
    {
        ms.Seek(0, SeekOrigin.Begin);
        
        XmlSerializer ser = new XmlSerializer(typeof(T));
        ser.Serialize(ms, Instance);
    }
    
    public void Deserialize()
    {
        ms.Seek(0, SeekOrigin.Begin);

        XmlSerializer ser = new XmlSerializer(typeof(T));
        Instance = (T)ser.Deserialize(ms);
    }
}

The trick here is that this is a generic type and each time the serializer is invoked it creates a new serialization assembly specific to the generic type (T) using which this type is created. This way the Response base-class doesn't need to know about all its descendants in order to be able to serialize itself. There is a performance penalty though, the Xml serializer will create a so-called serialization assembly for each generic type. Fortunatly there are ways to improve the Xml serializer's performance.

The real power of this approach becomes apparant when doing late instantiation of the generic parameter type (ie; not knowing the exact generic parameter type at compile-time).

I have created a small sample project to demonstrate this approach. You can download it here.

Hope this helps somebody.

Comments

# Marc Jacobi said on Thursday, November 23, 2006 12:40 AM

....but, this would work, wouldn't it?

void SerializeResponse(Response response)

{

   using (MemoryStream ms = new MemoryStream())

   {

       XmlSerializer ser = new XmlSerializer(response.GetType());

       ser.Serialize(ms, response);

   }

}

# Waseem Sadiq said on Thursday, November 23, 2006 1:05 AM

You are absolutely right, that's a nice trick :-)

But still this approach is preferred in situations where you are doing a lot of late-bound instantiation.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 8 and 5 and type the answer here: