Introduction
The article describes how to serialize an object of a class inherited from generic list of interface (i.e., List<InterfaceName>
) using XML serialization. I've developed the sample project in ASP.NET 3.5 but the same code can be used in .NET 2.0.
Here, I'm assuming that you know the basic implementation of IXmlSerializable
interface. IXmlSerializable
interface exposes three methods, GetSchema()
, ReadXML()
and WriteXML()
. We will return null
from GetSchema()
and add code to ReadXML()
and WriteXML()
function.
Background
There was a requirement to create a Workflow engine in one of the projects I was working on. This workflow engine (object of type WorkFlow class) contains workflow items and executes them one by one and then moves to the next.
Any item of workflow should contain Execute
method and ExecutionCompleted
event. So I created an interface named IWorkFlowItem
which contains the Execute
method and the ExecutionCompleted
event plus several common properties. Initially, I required two workflow items, i.e., Page
and Condition
. I created these two by implementing IWorkFlowItem
interface. Then I created a class WorkFlowItems
by inheriting generic List<IWorkFlowItem>
and added a member of this type to the main Workflow
class.
Everything worked fine till one requirement came to serialize the workflow
object and save it. It threw me an error when I tried to serialize it. In the beginning, I implemented the WorkFlowItems
class with IXmlSerializer
and put a dirty code to serialize the class in ReadXml()
and WriteXml()
methods. But, because the type of workflow items can increase to any extent, this solution was of no use. Finally, I came up with a solution and am sharing it with you.
I couldn't put the actual code and am putting here a different example, but it will give you the exact picture of my implementation of interface serialization.
Why XML Serializer Cannot Serialize an Interface?
Have a look at the definitions of the classes used for this example:





Now have a look at the use of project class:

The above serialization code will throw an error because IProjectMember
is not an object, it's an interface. An interface can only access members of the object by pointing to the same location in memory and it is limited to access only those members which are in scope of its own. That says the IProjectMember
interface can only access Name
, TotalHoursWorked
and Responsibilities
properties of an object that implements it.
Again, if somehow, we were able to serialize the properties that IProjectMember
exposes, we would have got a serialized XML, something like this:

The problem with the above serialization is:
- We don't know what type of object an
IProjectMember
exposes. Is it a SoftwareDeveloper
or a ProjectLeader
? - We don't have additional properties specific to an object, that means while deserializing, we don't have actual state of the object.
- On top-of-all,
IProjectMember
is an interface so you cannot create an instance of it. That means all the above points are null
.
The Idea to Solve this Problem
We need an XML like given below to persist the actual state of the SoftwareProject
object.

The bad thing about an interface is, you cannot create an object out of it, but the good thing is that it points to an object (Instance of a class). Every object in .NET is, by default, inherited from object
base class. I've always wondered why .NET has inherited every object from the base object
class but it was a life saver for me in this case. The GetType()
method of an object returns the actual type of that object. We will see that how I've used this method to solve this problem in 'Understanding the Code' section.
Ok, enough story, have a look at the ideas to serialize and deserialize the object/xml.
To serialize:
The idea is to get the exact type of object to which an interface item is pointing while iterating the list. Say, for the first interface item in the Members
list, it is pointing to ProjectLeader
object while the second object is pointing to SoftwareDeveloper
object. After getting the type, cast that object to that type and serialize it and then write the serialized data on the XML writer stream in WriteXml()
method.
To deserialize:
To deserialize, we need to convert the XML to an object. For this, the ReadXML()
method of IXMLSerializable
interface provides xmlReader
parser. We will iterate through the items of SoftwareProject
node. Each child node name represents the actual class name. While iterating through items, we can create a XMLSerializer
to deserialize the data and can use Type.GetType(ClassName)
to pass the type as input parameter to this XMLSerializer
.
Understanding the Code
Files Description
- IProjectMember.cs - Interface defining common properties/methods for a project member. The generic list of this interface will be serialized.
- ProjectLeader.cs - Class to be used as a item for generic list to serialize.
- SoftwareDeveloper.cs - Class to be used as a item for generic list to serialize.
- ProjectTeam.cs - Class inherited from generic list of
IProjectMember
that is being serialized. - Project.cs - Class defining root object to hold
ProjectTeam
as a member to hold all the software developers and project leaders. - GenericListSerializer.cs - Class to XML serialize a generic list of type interface.
- GenericListDeSerializer.cs - Class to XML deserialize a generic list of type interface.
Interface to Define a Project Member
namespace SerializableList
{
public interface IProjectMember
{
string Name { get; set; }
int TotalHoursWorked { get; set; }
string Responsibilities { get; set; }
}
}
Project Team Class
namespace SerializableList
{
public class ProjectTeam : List<IProjectMember>, IXmlSerializable
{
#region IXmlSerializable Members
public XmlSchema GetSchema()
{ return null; }
public void ReadXml(XmlReader reader)
{
GenericListDeSerializer<IProjectMember> dslzr =
new GenericListDeSerializer<IProjectMember>();
dslzr.Deserialize(reader, this);
}
public void WriteXml(XmlWriter writer)
{
GenericListSerializer<IProjectMember> serializers =
new GenericListSerializer<IProjectMember>(this);
serializers.Serialize(writer);
}
#endregion
}
}
To implement IXmlSerializable
interface, the class should implement these three methods:
GetSchema()
- In the current case, I'm returning null
. ReadXml()
- This function is used to deserialize the object (converting XML to original object). In this function, I've created an object of GenericListDeSerializer<IProjectMember>
and passed the current reader stream and current object to its Deserialize(..)
method. WriteXml()
- This function is used to serialize the object(converting the original object to XML). In this function, I've created an object of GenericListSerializer<IProjectMember>
and then pass the current writer stream to its Serialize(..)
method.
To instantiate XmlSerializer
object, we require to pass a Type
as a constructor parameter. Now, in the current scenario, because the list will contain different type of objects, we need to keep a list of every type of XmlSerializer
, so that the list item can be serialized/deserialized with that specific XmlSerializer
.
In the sample application, I've used Dictionary<key,value>
to hold a list of XmlSerializer
. Here, type name is the key
and XmlSerializer
object is the value. The GetSerializerByTypeName(string typeName)
is used to find and add XmlSerializer
object from this Dictionary<key, value>
object.
Generic List Serializer
namespace SerializableList
{
public class GenericListSerializer<T>
{
private List<T> _interfaceList;
private Dictionary<string, XmlSerializer> serializers;
public GenericListSerializer(List<T> interfaceList)
{
_interfaceList = interfaceList;
InitializeSerializers();
}
private void InitializeSerializers()
{
serializers = new Dictionary<string, XmlSerializer>();
for (int index = 0; index < _interfaceList.Count; index++)
{
GetSerializerByTypeName(
_interfaceList[index].GetType().FullName);
}
}
public void Serialize(XmlWriter outputStream)
{
for (int index = 0; index < _interfaceList.Count; index++)
{
GetSerializerByTypeName(
_interfaceList[index].GetType().FullName).Serialize
(outputStream, _interfaceList[index]);
}
}
private XmlSerializer GetSerializerByTypeName(string typeName)
{
XmlSerializer returnSerializer = null;
if (serializers.ContainsKey(typeName))
{
returnSerializer = serializers[typeName];
}
if (returnSerializer == null)
{
returnSerializer = new XmlSerializer(
Type.GetType(typeName));
serializers.Add(typeName, returnSerializer);
}
return returnSerializer;
}
}
}
The GenericListSerializer<T>
class exposes one constructor GenericListSerializer(List<T> interfaceList)
and one public
method - Serialize(XmlWriter outputStream)
.
GenericListSerializer(List<T> interfaceList)
- The constructor accepts the generic list to be serialized as an input parameter and invokes InitializeSerializers()
method to create a list of XmlSerializer
.
Serialize(System.Xml.XmlWriter outputStream)
- This is the main method which serializes the generic list when invoked. It iterates through each item of generic list, while iterating, it gets the class type name of current item with CurrentItem.GetType().Name
method and passes this to GetSerializerByTypeName()
method to retrive appropriate XmlSerializer
object. After getting XmlSerializer
, it then invokes Serialize
method and passes main XmlWriter
output stream and current item(of generic list) to serialize.
Generic List Deserializer
namespace SerializableList
{
public class GenericListDeSerializer<t>
{
private Dictionary<string, XmlSerializer> serializers;
public GenericListDeSerializer()
{
serializers = new Dictionary<string, XmlSerializer>();
}
public void Deserialize(XmlReader inputStream, List<T> interfaceList)
{
string parentNodeName = inputStream.Name;
inputStream.Read();
while (parentNodeName != inputStream.Name)
{
XmlSerializer slzr = GetSerializerByTypeName(
inputStream.Name);
interfaceList.Add((T)slzr.Deserialize(inputStream));
}
}
private XmlSerializer GetSerializerByTypeName(string typeName)
{
XmlSerializer returnSerializer = null;
if (serializers.ContainsKey(typeName))
{
returnSerializer = serializers[typeName];
}
if (returnSerializer == null)
{
returnSerializer = new XmlSerializer(Type.GetType(
Type.GetType(this.GetType().Namespace + "." +
typeName));
serializers.Add(typeName, returnSerializer);
}
return returnSerializer;
}
}
}</t>
The GenericListDeSerializer<T>
class exposes one public
method - Deserialize(XmlReader inputStream, List<T> interfaceList)
.
Deserialize(System.Xml.XmlReader inputStream, List<T> interfaceList)
- This method deserializes the serialized object. It accepts two input parameters, XmlReader
input stream and the generic list object to which deserialized objects will be added.
When the main XmlSerializer
passes XmlReader
stream to ReadXml()
method of ProjectTeam
class, the reader's pointer is located at <Members>
tag. It is the member property name of type ProjectTeam
in SoftwareProject
class. This acts as a root node for all items in generic list of type IProjectMember
.

parentNodeName
variable is used to hold the name of root node so that the deserializer can deserialize all the items until it reaches the end node, i.e., </Members>
inputStream.Read();
forwards the reader position to first child node, i.e., <ProjectLeader>
while (parentNodeName != inputStream.Name)
keeps a track of the scope of <Members>
node. When it reaches the end node, i.e., </Members>
, this condition will return false
and the loop will be terminated.
XmlSerializer slzr = GetSerializerByTypeName(inputStream.Name);
fetches the appropriate XmlSerializer
from stream
by passing the class name as a key. interfaceList.Add((T)slzr.Deserialize(inputStream));
adds the deserialized object to the passed generic list. Here, I'm casting the deserialized object to the IProjectMember
interface. When slzr.Deserialize(...)
gets invoked, it deserializes the current node, i.e., <ProjectLeader>/<SoftwareDeveloper>
and advances the reader to the next child node.
Limitations
- There are no additional properties in
ProjectTeam :
List<IProjectMember>
class, because for that, we may need to handle the processing manually. But for now, I've not focused on that. - I've given all the sample code in this tutorial with the namespace. This is because the
GenericListDeSerializer<T>
class should be in same namespace, otherwise it will throw an error while invoking Type.GetType(string typeName)
. This is because the GetType
requires a fully qualified assembly name in this case, it is SerializableList.ProjectLeader
or SerializableList.SoftwareDeveloper
. So with the help of this.GetType().Namespace
property and child node name <ProjectLeader>/<SoftwareDeveloper>
fully qualified name is being passed to Type.GetType(..)
method. - I used
Type.GetType().FullName
property to get fully qualified assembly name of the type because while serializing the object, it throws an error if only class name is passed.