共用方式為


How to Serialize a Dictionary or Hashtable in C#

   This post kind of doesn't fit in with some of my other posts however, I had this question, and when I searched for answers on this, the answers I found were either incomplete, inneficient or outdated. So to make it easy for everyone, I'm writing this complete and up to date blog post (well as of this date any way!).

   This post was written using .NET Framework 4.0 and storing my data in SQL Server 2008.

   Let's take a look at the problem I had at hand. I needed to be able to store Key\Value pairs from a C# application into SQL. Since I did not know how many key value pairs I might end up with I decided to use the Dictionary object in c#. The problem is, both the Dictionary and Hashtable classes or not serializabe because they implement the IDictionary interface. Here's the error that you will get if you try to serialize one of the classes:

System.NotSupportedException was unhandled
Message=The type System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] is not supported because it implements IDictionary.
Source=System.Xml
StackTrace:
at System.Xml.Serialization.TypeScope.GetDefaultIndexer(Type type, String memberInfo)
at System.Xml.Serialization.TypeScope.ImportTypeDesc(Type type, MemberInfo memberInfo, Boolean directReference)
at System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source, Boolean directReference, Boolean throwOnError)
...

   The reason the System.NotSupportedException is thrown is because the IDictionary class implements the IXmlSerializable interface.The IXmlSerializable interface makes us overide the following methods: GetSchema, ReadXml and WriteXml. We can do this, but since we have to write a class to overide these functions anyway, it's easier to just write a generic class and use that for serialization. Let's take a look.

   What we are going to do is make a stub class that will be serializbe that mimics the Dictionary or Hashtable DictionaryItem or KeyValuePair<string, string>. We want this class to be a simple a possible:

public class DataItem
{

public string Key;

public string Value;

public DataItem(string key, string value)

{

Key = key;

Value = value;

}

  Now we will use the System.Generics.List  to mimic the dictionary or hashtable classes: 

List<DataItem> tempdataitems = new List<DataItem>(myDictionary.Count);

   Since this is now serializable, we can jjust foreach through our Dictionary or Hashtable objects and build our tempdataitmes class to serialize.

foreach (string key in myDictionary.Keys)

{

tempdataitems.Add(new DataItem(key, myDictionary[key].ToString()));

}

   The last thing I need to do is serialize this to a string so I can now store it in my SQL database with the column type of XML.

private string SerializeJobData()

{

   List<DataItem> tempdataitems = new List<DataItem>(myDictionary.Count);

   foreach (string key in dataitems.Keys)

   {

       tempdataitems.Add(new DataItem(key, dataitems[key].ToString()));

   }

   XmlSerializer serializer = new XmlSerializer(typeof(List<DataItem>));

   StringWriter sw = new StringWriter();

   XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

   ns.Add("","");

   serializer.Serialize(sw, tempdataitems,ns);

   return sw.ToString();

}

   In this example I am using the .net 4 StringWriter class from the System.IO namespace. This makes working with the stream needed for xml serialization simple because it hanldes the stream needed for xml serialization. In addtion you can see that I didn't want the default .net namespace in my xml so I set the namespace of the xmlsericalizer to "". If you want more control over your xml be sure to include your custom namespace.

   Here's what the data looks like in SQL:

<ArrayOfDataItem>

  <DataItem>

    <Key>Vera</Key>

    <Value>Vera</Value>

  </DataItem>

  <DataItem>

    <Key>David</Key>

    <Value>David</Value>

  </DataItem>

  <DataItem>

    <Key>Susan</Key>

    <Value>Susan</Value>

  </DataItem>

  <DataItem>

    <Key>FakeParam</Key>

    <Value>FakeParam</Value>

  </DataItem>

</ArrayOfDataItem> 

   As you can see this is nice and clean.

   The last thing we would need to tacke is deserializing back to a Dictionary<string, string> object. I'm going to again use the StringWriter class to help me.

private void DeserializeData(string RawData)

{

   Dictionary<string, string> myDictionary = new Dictionary<string, string>();

  XmlSerializer xs = new XmlSerializer(typeof(List<DataItem>));

  StringReader sr = new StringReader(RawData);

   List<DataItem> templist = (List<DataItem>)xs.Deserialize(sr);

   foreach (DataItem di in templist)

   {

       myDictionary.Add(di.Key, di.Value);

   }

}

   Super simple!

   I hope this helps you quicly get through this task and answers all questions regarding serializing and deserialize the .net 4 Dictionary and Hashtable classes.

Comments

  • Anonymous
    December 19, 2010
    Good Solution,I was googling for simple solution finally got.Now I am trying to implement.Thank you for sharing.

  • Anonymous
    December 19, 2010
    Example is missing. You must have created a sample.Plz shareanjumrizwi@gmail.com

  • Anonymous
    February 09, 2011
    make sure to add a parameterless constuctor to the dataitem classelse it wont compile (not shown in code above)

  • Anonymous
    May 03, 2011
    you could alternatively use a keyedcollection.

  • Anonymous
    March 06, 2012
    The comment has been removed

  • Anonymous
    May 23, 2012
    Hi, I tried serializing my dictionary your way.I am having string and list as KeyValuePair<string,list>. When i am seriailizing, the <key>...</key><value>...</value> nodes are not coming.Some steps are missing with your code or i am misleading somewhere. Can someone please help it on?

  • Anonymous
    August 23, 2012
    This is simple and brilliant. Far better than creating a serializable dictionary that implements IXmlSerializable

  • Anonymous
    April 23, 2014
    Worked like a charm! this is amazing.. .thank you

  • Anonymous
    August 03, 2015
    What is working like a charm? The code is not complete. Couple of people said that already. If you care please share the complete code.

  • Anonymous
    September 17, 2015
    Simple, but very effective idea to serialize the class having Dictionary types!