Generic Dictionaries vs. the XmlSerializer

Share this article

One of the neatest new features of .NET 2.0 is the concept of Generics. And one of the most common uses of this feature is in the new GenericCollections. Anyone who spent quality time extending CollectionBase and DictionaryBase in 1.1 (or just cheating using CodeSmith’s collection gen) will understand how useful these collections are.

Another of the very handy features of .NET is the built-in, nearly automagic XmlSerialization. Presuming one follows a few simple rules—principally having a blank, default constructor and making sure all properties implement Get and Set accessors—one can instantaneously serialze any object to Xml. This tactic, unfortunately, falls apart when one attempts to make use of the new Generic dictionary as a member of an object one wishes to XmlSerialize. Rather than a bit of xml, you get a nice little exception stating “There was an error reflecting type ‘your type name here’”.

There are a number of ways to workaround this issue. Most involve implementing IXmlSerializable, which tends to lead to writing a lot of repetitive code. And these techniques are a good option if you are writing to and reading from a very specific schema. However, many times, one just needs to get something serialized in a quick and dirty, but working manner for use with, say, some internal Web Service or some kind of temporary storage.

In that case, one can use the following technique:

  1. First, decorate the Dictionary<TKey, TValue> property with an XmlIgnore attribute. This tells the XmlSerializer to ignore that property, eliminating the reflection error.
  2. Create a new public property that takes and returns an array of DictionaryEntry objects. I tend to name these specially (_x_DictionaryName) so that it is clear one should not generally use this property.
  3. Serialize away.

 

In case the above is a bit obtuse, see below for an example:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace SPBlog.DictionarySerialization
{
    [XmlRoot("StuffContainer")]
    public class Serializable
    {
        public Serializable() { }

        private Dictionary<string, int> stuff=new Dictionary<string,int>();
        
        /// <summary>
        /// Public stuff dictionary.
        /// </summary>
        /// <remarks>
        /// Note the XmlIgnore attribute.
        /// </remarks>
        [XmlIgnore()]
        public Dictionary<string, int> Stuff
        {
            set { stuff = value; }
            get { return stuff; }
        }

        
        /// <summary>
        /// Property created expressly for the XmlSerializer
        /// </summary>
        /// <remarks>
        /// Note the XML Serialiazation attributes; they control what elements are named when this object is serialized.
        /// </remarks>
        [XmlArray("Stuff")]
        [XmlArrayItem("StuffLine", Type=typeof(DictionaryEntry))]
        public DictionaryEntry[] _x_Stuff
        {
            get
            {
                //Make an array of DictionaryEntries to return
                DictionaryEntry[] ret=new DictionaryEntry[Stuff.Count];
                int i=0;
                DictionaryEntry de;
                //Iterate through Stuff to load items into the array.
                foreach (KeyValuePair<string, int> stuffLine in Stuff)
                {
                    de = new DictionaryEntry();
                    de.Key = stuffLine.Key;
                    de.Value = stuffLine.Value;
                    ret[i]=de;
                    i++;
                }
                return ret;
            }
            set
            {
                Stuff.Clear();
                for (int i=0; i<value.Length; i++)
                {
                    Stuff.Add((string)value[i].Key, (int)value[i].Value);
                }
            }
        }
    }
}

Which creates the following Xml:


<?xml version="1.0" encoding="utf-8"?>
<StuffContainer xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
  <Stuff>
    <StuffLine>
      <Key xsi:type="xsd:string">One</Key>
      <Value xsi:type="xsd:int">1</Value>
    </StuffLine>
    <StuffLine>
      <Key xsi:type="xsd:string">Two</Key>
      <Value xsi:type="xsd:int">2</Value>
    </StuffLine>
    <StuffLine>
      <Key xsi:type="xsd:string">Three</Key>
      <Value xsi:type="xsd:int">3</Value>
    </StuffLine>
    <StuffLine>
      <Key xsi:type="xsd:string">Four</Key>
      <Value xsi:type="xsd:int">4</Value>
    </StuffLine>
  </Stuff>
</StuffContainer>

Now, as you can see above, the DictionaryEntry deserializes in an interesting way—it adds a type attribute to the Key and Value nodes. One could easily modify this technique to use a custom object that serializes to specific types if one needs a bit more finite control of the output.

Frequently Asked Questions (FAQs) about Generic Dictionaries vs. The XMLSerializer

Why doesn’t XMLSerializer support Dictionary?

XMLSerializer does not inherently support Dictionary because of the way Dictionaries are structured. Dictionaries in .NET are a collection of key-value pairs, and the XMLSerializer does not have a built-in mechanism to handle this structure. However, there are workarounds to this, such as creating a custom class that mimics the behavior of a Dictionary and can be serialized by the XMLSerializer.

How can I serialize a Dictionary in C#?

To serialize a Dictionary in C#, you can create a custom class that mimics the behavior of a Dictionary. This class should contain a List of a custom KeyValuePair type. The KeyValuePair type should have properties for the key and value. Then, you can use the XMLSerializer to serialize this custom class.

What is the difference between Generic Dictionaries and XMLSerializer?

Generic Dictionaries and XMLSerializer are both used in .NET, but they serve different purposes. Generic Dictionaries are a type of collection that stores data as key-value pairs. On the other hand, XMLSerializer is a class that can be used to serialize and deserialize objects into and from XML documents.

Can I deserialize a Dictionary using XMLSerializer?

Yes, you can deserialize a Dictionary using XMLSerializer. However, since XMLSerializer does not inherently support Dictionaries, you will need to use a workaround. This involves creating a custom class that mimics the behavior of a Dictionary and can be serialized and deserialized by the XMLSerializer.

What are the limitations of XMLSerializer?

XMLSerializer has a few limitations. It does not support Dictionaries, it cannot process private fields, and it cannot handle read-only properties. Additionally, it can only serialize public fields and properties.

How can I overcome the limitations of XMLSerializer?

To overcome the limitations of XMLSerializer, you can create custom classes that mimic the behavior of the unsupported types. For example, to serialize a Dictionary, you can create a custom class that behaves like a Dictionary and can be serialized by the XMLSerializer.

What are the benefits of using Generic Dictionaries?

Generic Dictionaries in .NET offer several benefits. They provide fast access to values based on unique keys, they are strongly typed, and they can store different types of data.

Why should I use XMLSerializer?

XMLSerializer is a powerful tool for serializing and deserializing objects into and from XML documents. It is easy to use and can handle complex objects and object graphs. It is particularly useful when you need to store or transmit data in a standard, portable format.

Can I use XMLSerializer with other collection types?

Yes, XMLSerializer can be used with many other collection types in .NET, including Lists, Arrays, and ArrayLists. However, it does not inherently support Dictionaries.

Are there alternatives to XMLSerializer for serializing Dictionaries?

Yes, there are alternatives to XMLSerializer for serializing Dictionaries. One option is to use the DataContractSerializer, which does support Dictionaries. Another option is to use JSON.NET, which can serialize and deserialize Dictionaries to and from JSON.

Wyatt BarnettWyatt Barnett
View Author
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week