Click here to Skip to main content
13,291,748 members (56,430 online)
Click here to Skip to main content
Add your own
alternative version


22 bookmarked
Posted 8 Dec 2009

Simple Object Serializer

, 8 Dec 2009
Rate this:
Please Sign up or sign in to vote.
Simple object serializer using .NET Reflection and XML


How many times did you just want to build a simple client-server application via TCP/IP ? How many times did you mess around with the .NET Framework serializers (either XMLSerializer or BinarySerializer) to get your data objects sent correctly across the network ? Don't struggle anymore, take a look at the simple serialization approach described in this article. No need to mess around with MarshalByRefObject, XML Attribute classes a.s.o. any more.


(If you are not familiar with the .NET Reflection namespace, I suggest you have a look at one of the tutorials about Reflection here at CodeProject first before reading this article. Otherwise the code presented here might seem a little cryptic and confusing.

Using the Code

Ok, let's get started. What we are going to do is develop a custom serializer which transforms any given object into a string in XML-format. In this article, I will limit the functionality of the serializer to serializing / deserializing objects which consist of Primitives, Enums, Lists (generic and non-generic) and Dictionaries (generic dictionary, Hashtable) as well as nested combinations of these basic types. The serializer will basically loop recursively through the given input and transform it to the requested output. For the process of serializing, the input will be an object instance which is limited to the usage of types specified above and the output will be a string instance containing an XML document. For the process of deserialization, the roles of input and output are swapped accordingly.

Following this thought, for the user of our serializer class, we will need just two public methods:

  • public string Serialize(object input);
  • public object Deserialize(string input);
namespace MySerialization
  public class NullValue
    public NullValue()

  public class ObjectSerializer
    public static string Serialize(object input)
      //Create the xml document instance we are going to work with as well as
      //a main element node
      XmlDocument doc = new XmlDocument();
      XmlNode mainElement = doc.CreateNode(XmlNodeType.Element, "Instance", "");
      if (input != null)
        //We need to store the type information of the input object, because we
        //will need it to deserialize this again later. The type information is
        //stored in an attribute of the main element node.
        XmlAttribute att = doc.CreateAttribute("Type");
        att.Value = input.GetType().AssemblyQualifiedName;

        //Add the main element node to the xml document.

        //Here we enter the recursion, passing the xml document instance, the parent
        //xml node of the next recursion level and the parent object of the next 
        //recursion level in as parameters. Because the xml document instance and the 
        //node element are reference types (classes) we don't need a "ref" here.
        //The object could be a value type like a primitive or an enum, but as we are
        //serializing, we will only need read access to the object, so no "ref" needed
        //here either.
        SerializeRecursive(doc, mainElement, input);
        //At the end of the recursion, we return the string representation of our xml
        //document instance.
        return doc.InnerXml;
        //During deserialization, we would get in trouble if we were trying to retrieve
        //type information of a null value. Therefore we replace any null values with a
        //dummy instance of a type NullValue.
        return Serialize(new NullValue());
    public static object Deserialize(string input)
      //We put the input string back into an xml document instance. This will make life
      //easier in the recursion, because we can loop through the xml node objects.
      XmlDocument doc = new XmlDocument();
      //Retrieve the type of the serialized object, using the Type-Attribute we added 
      //during the serialization. Using this type information, we can create an instance
      //of this type.
      Type mainType = Type.GetType(doc.DocumentElement.Attributes["Type"].Value);
      object result = Activator.CreateInstance(mainType);

      //Any NullValue instances we created during serialization 
      //to replace null values will
      //be transformed back into null values.
      if (result is NullValue)
        result = null;

      if (result != null)
        //Now we get all properties of our object type so we can start recursion.
        PropertyInfo[] properties = mainType.GetProperties();
        foreach (PropertyInfo pi in properties)
          //For this article we exclude indexed properties like type accessors.
          ParameterInfo[] paramInfos = pi.GetIndexParameters();
          if (paramInfos.Length == 0)
            DeserializeRecursive(pi, result, doc.DocumentElement);

      return result;

Note that in this article, for the matter of simplicity, we expect that the assemblies which contain the types we are serializing/deserializing are known to each process in the application. In a more universal context, we could also store the assembly information of the assemblies which contain our types, using a second XmlAttribute we could attach to the instance node. That way, we could load that assembly during deserialization and take the type of our serialized object out of that assembly. We could do that in every stage during the recursion but keep in mind that this blows up the size of your XML file big time, so you should ask yourself if you really need this flexibility or if you can live with the limitation that all processes know your types already.

Next we will take a look at the SerializeRecursive method and the different cases it handles:

  • Primitives
  • Enum Types
  • List Types
  • Dictionary Types
namespace MySerialization
  public class NullValue
    public NullValue()

  public class ObjectSerializer
    public static string Serialize(object input)
    public static object Deserialize(string input)
    //Keep in mind that the xml node is the parent node 
    //and the object is the parent object of the 
    //subobject we are going to serialize in the current recursion level.
    private static void SerializeRecursive
	(XmlDocument doc, XmlNode parentNode, object parentObject)
      //Handle null value by using a NullValue instance as replacement.
      object o = new NullValue();
      if (parentObject != null)
        o = parentObject;

      Type objType = o.GetType();

      //Case 1: Parent object is a primitive or an enum (or a string)
      if (objType.IsPrimitive || objType.IsEnum)
        //If our parent object is a primitive or an enum type, 
        //we have reached a leaf in the recursion.
        //A leaf always ends in a concrete value, 
        //which we then store as value of the last parent xml
        parentNode.InnerText = o.ToString();        
      else if (objType == typeof(string))
        //The string type has to be handled separately, 
        //because it doesn't count as a primitive.
        parentNode.InnerText = (string)o;
      //Case 2: Parent object is a list type
      else if (typeof(IList).IsAssignableFrom(objType))
        //Unbox the list and loop through all elements, 
        //entering the next recursion level.
        IList tempList = (IList)o;        
        foreach (object i in tempList)
          //For each entry in the list, 
          //we create a child node "ListEntry" and add it below
          //out current parent node.
          XmlNode node = doc.CreateNode(XmlNodeType.Element, "ListEntry", "");

          //Below the ListEntry node, we add another child node 
          //which contains the value of
          //the list item.
          XmlNode valueNode = doc.CreateNode(XmlNodeType.Element, "Value", "");          
          //Handle the case when the list item is a null value, 
          //by replacing it with a NullValue
          object item = new NullValue();
          if (i != null)
            item = i;

          //Save the type information of the list item object for deserialization.
          //We add this type info as an attribute, 
          //in the same way we did with the main document
          XmlAttribute att = doc.CreateAttribute("Type");
          att.Value = item.GetType().AssemblyQualifiedName;
          //Enter the next recursion step, using the valueNode 
          //as new parent node and the list item
          //as new parent object.
          SerializeRecursive(doc, valueNode, item);

      //Case 3: Parent object is a dictionary type.
      else if (typeof(IDictionary).IsAssignableFrom(objType))
        //This case works in about the same way as the list type serialization above
        //and should be quite self-explainatory if you understood the list case.
        //The only difference here is that the recursion tree will split into two
        //branches here, one for the key and one for the value of each dictionary
        IDictionary tempDictionary = (IDictionary)o;
        foreach (object key in tempDictionary.Keys)
          XmlNode node = doc.CreateNode(XmlNodeType.Element, "DictionaryEntry", "");

          XmlNode keyNode = doc.CreateNode(XmlNodeType.Element, "Key", "");
          XmlAttribute kAtt = doc.CreateAttribute("Type");
          kAtt.Value = key.GetType().AssemblyQualifiedName;

          SerializeRecursive(doc, keyNode, key);

          XmlNode valueNode = doc.CreateNode(XmlNodeType.Element, "Value", "");
          XmlAttribute vAtt = doc.CreateAttribute("Type");

          object entry = new NullValue();
          if (tempDictionary[key] != null)
            entry = tempDictionary[key];

          vAtt.Value = entry.GetType().AssemblyQualifiedName;

          SerializeRecursive(doc, valueNode, entry);
      //Case 4: Parent object is a complex type (class or struct)
        //This case looks similar to what we did in the original Serialize() method.
        //First we get all properties of the current object, then we loop through them,
        //continuing the recursion.
        PropertyInfo[] properties = objType.GetProperties();
        foreach (PropertyInfo pi in properties)
          //Exclude indexed properties
          ParameterInfo[] test = pi.GetIndexParameters();
          if (test.Length == 0)
            XmlNode node = doc.CreateNode(XmlNodeType.Element, pi.Name, "");
            XmlAttribute att = doc.CreateAttribute("Type");
            att.Value = pi.PropertyType.AssemblyQualifiedName;
            //Get the concrete value of the current property in the parent object
            //so we can continue recursion based on that value object.
            SerializeRecursive(doc, node, pi.GetValue(o, null));

If you worked through this recursive method and understood all cases and how they work, the DeserializeRecursive() method will be self-explanatory. You can find it annotated in the sample code attached to this article.

Points of Interest

The code in this example is meant to demonstrate the basics behind the idea. It does not contain any error handling and it does not handle "unhandled" types. Therefore I don't recommend to use it in a project as is.

Basically this serializer can handle any class or struct objects which contain only primitives, enums, strings, Lists and Dictionaries or class/struct objects which also only contain these basic types.

Keep in mind that there are some objects which cannot be serialized like Forms, Controls, Type or Assembly objects. Before you use this approach in one of your projects, you should handle these types accordingly.


  • Version 1.0: Running ObjectSerializer without error handling


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer BSA Both Automation
Germany Germany
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralProblem in Parent child relation Pin
saiful_vonair9-Dec-09 0:17
membersaiful_vonair9-Dec-09 0:17 
GeneralRe: Problem in Parent child relation Pin
Thorsten_Loos9-Dec-09 2:38
memberThorsten_Loos9-Dec-09 2:38 
GeneralCould be much better Pin
SAKryukov8-Dec-09 13:42
memberSAKryukov8-Dec-09 13:42 
GeneralRe: Could be much better Pin
Thorsten_Loos9-Dec-09 2:50
memberThorsten_Loos9-Dec-09 2:50 
GeneralIt is actually quite bad Pin
SAKryukov9-Dec-09 5:07
memberSAKryukov9-Dec-09 5:07 
Thorsten_Loos wrote:
First of all, I don't see your striking problem. Where do you see string constants dispersed through the code?

Could you give an example ? Maybe I just don't understand what you mean.

Sure. All your string literals literals"DictionaryValue", "Value", "Key" introduce 'immediate constants' throughout the code. Not only they are excessive: this style of coding is very bad; it makes the code unsupportable.

Thorsten_Loos wrote:
The objects do have an object graph deeper than three

Sorry, this is gibberish. The concept of three does not imply limitation by depth (a graph "deeper then tree" is still a tree). Instead, a tree is by definition a graph without circles, so let's go a step further...

Thorsten_Loos wrote:
However if you really need circular references (which generally is a sign of a design error imo), you would have to either extend the code using object hashing so

I see now. Well, thank you for your confession. Now some of Microsoft solutions as well as some works published in CodeProject easily solve the problem of circular references, which is fundamentally important. Before writing your own article you could study cite them, then examine if your code has any value for the readers.
Circular references is now way a "design error" and are fundamentally important; I just don't have time to give you examples.
You just created an ad-hoc solution and I don't know why you decided to publish it.

Sorry, your work did not deserve my 3 (but I did not change my vote).
Actually, the article had negative value, because it distracts your readers from really worthy solutions and waist their time.

Sergey A Kryukov

GeneralRe: It is actually quite bad Pin
Thorsten_Loos9-Dec-09 11:14
memberThorsten_Loos9-Dec-09 11:14 
GeneralExcuses? (Re: It is actually quite bad) Pin
SAKryukov10-Dec-09 16:26
memberSAKryukov10-Dec-09 16:26 
GeneralRe: Excuses? (Re: It is actually quite bad) Pin
Thorsten_Loos16-Dec-09 5:13
memberThorsten_Loos16-Dec-09 5:13 
GeneralRe: It is actually quite bad Pin
Arribajuan23-Dec-09 9:40
memberArribajuan23-Dec-09 9:40 
GeneralRe: It is actually quite bad Pin
SAKryukov23-Dec-09 13:58
memberSAKryukov23-Dec-09 13:58 
GeneralRe: It is actually quite bad Pin
Thorsten_Loos4-Jan-10 18:45
memberThorsten_Loos4-Jan-10 18:45 
GeneralWhatever you say Pin
SAKryukov4-Jan-10 20:05
memberSAKryukov4-Jan-10 20:05 
GeneralMy vote of 2 Pin
Gilad Kapelushnik8-Dec-09 7:43
memberGilad Kapelushnik8-Dec-09 7:43 
GeneralGood idea but around 3 years late... Pin
Gilad Kapelushnik8-Dec-09 7:42
memberGilad Kapelushnik8-Dec-09 7:42 
GeneralRe: Good idea but around 3 years late... Pin
Thorsten_Loos8-Dec-09 11:10
memberThorsten_Loos8-Dec-09 11:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171207.1 | Last Updated 8 Dec 2009
Article Copyright 2009 by Thorsten_Loos
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid