Are Hashtables Serializable?

10,364

Solution 1

The pervasive belief is so pervasive because it's true:

var t = new Hashtable();
t.Add("Hi!", "I'm here");
t.Add("Hm", "Yup");

var serializer = new XmlSerializer(typeof(Hashtable));

using (var sw = new StringWriter())
{
  serializer.Serialize(sw, t);

  Console.WriteLine(sw.ToString());
}

throws

NotSupportedException: The type System.Collections.Hashtable is not supported because it implements IDictionary.

That doesn't mean that it's literally impossible to serialize a hash table. Of course I can just iterate over all the keys and values, write them to a string and then reconstruct the hashtable from that. It's just that I can't use the serialization infrastructure fully.

What's the reasoning here? It's actually quite simple - XmlSerializer is designed to produce good XML, in the spirit of the interchange format XML was designed to be. And XML doesn't have any kind of dictionary or "key-value" mechanism that would fit. So to support hashtable serialization, they'd have to make their own "sub-format" with its own rules. And back when .NET was being designed, this was a huge no-no - XML was an interchange format. Any extension (hah) to the format means you're no longer compatible, no matter how good of an idea you have.

Of course, nowadays, everyone and their grandmother are producing XML data that isn't used for interchange purposes. And it's not entirely a bad thing (after all, .NET config files are also a XML format). But it's also kind of wrong.

In contrast, take something like BinaryFormatter. That's a class where the .NET team designed the whole format, and isn't limited by a standard. And lo and behold - BinaryFormatter can serialize and deserialize a Hashtable just fine.

So the slightly more correct belief would be "Hashtable cannot be serialized to valid standard XML. The XmlSerializer class in particular will throw an error when you attempt to serialize a Hashtable."

Solution 2

Does Hashtable implement ISerializable? Absolutely:

public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable

Can we serializae a Hashtable to XML? Let's try it:

        var hash = new System.Collections.Hashtable();
        hash[7] = "7";
        hash[8] = "8";
        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Hashtable));
        TextWriter writer = new System.IO.StreamWriter(@"C:\SomeFile.xml");
        serializer.Serialize(writer, hash);

Result... Error as you expected

An exception of type 'System.NotSupportedException' occurred in System.Xml.dll but was not handled in user code

Additional information: The type System.Collections.Hashtable is not supported because it implements IDictionary.

So, it would appear that indeed, it's still the case in .Net 4.5+

But lets try one more time with a binary serialization...

        var hash = new System.Collections.Hashtable();
        hash[7] = "7";
        hash[8] = "8";
        var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        Stream stream = new FileStream(@"C:\SomeFolder\SomeFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
        formatter.Serialize(stream, hash);
        stream.Close();

Result... No Errors thrown... So the issue appears to be related to IDictionary and XmlSerialization, but not all Serialization

If you really need to do this to XML, ManoDestra had a nice link https://blogs.msdn.microsoft.com/adam/2010/09/10/how-to-serialize-a-dictionary-or-hashtable-in-c/

Also, interestingly, XML Serialization mentions that you can't serialize unsigned longs or collections there-of.

Microsoft XML Serialization (MSDN)

Solution 3

Microsoft seems to say that it is certainly possible to do this. https://msdn.microsoft.com/en-us/library/b85344hz(v=vs.110).aspx

using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

public class App 
{
    [STAThread]
    static void Main() 
    {
        Serialize();
        Deserialize();
    }

static void Serialize() 
{
    // Create a hashtable of values that will eventually be serialized.
    Hashtable addresses = new Hashtable();
    addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052");
    addresses.Add("Fred", "987 Pine Road, Phila., PA 19116");
    addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");

    // To serialize the hashtable and its key/value pairs,  
    // you must first open a stream for writing. 
    // In this case, use a file stream.
    FileStream fs = new FileStream("DataFile.dat", FileMode.Create);

    // Construct a BinaryFormatter and use it to serialize the data to the stream.
    BinaryFormatter formatter = new BinaryFormatter();
    try 
    {
        formatter.Serialize(fs, addresses);
    }
    catch (SerializationException e) 
    {
        Console.WriteLine("Failed to serialize. Reason: " + e.Message);
        throw;
    }
    finally 
    {
        fs.Close();
    }
}


static void Deserialize() 
{
    // Declare the hashtable reference.
    Hashtable addresses  = null;

    // Open the file containing the data that you want to deserialize.
    FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
    try 
    {
        BinaryFormatter formatter = new BinaryFormatter();

        // Deserialize the hashtable from the file and 
        // assign the reference to the local variable.
        addresses = (Hashtable) formatter.Deserialize(fs);
    }
    catch (SerializationException e) 
    {
        Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
        throw;
    }
    finally 
    {
        fs.Close();
    }

    // To prove that the table deserialized correctly, 
    // display the key/value pairs.
    foreach (DictionaryEntry de in addresses) 
    {
        Console.WriteLine("{0} lives at {1}.", de.Key, de.Value);
    }
}
}
Share:
10,364

Related videos on Youtube

Thomas
Author by

Thomas

My background is in Comparative Religious Theory and East Asian Studies - a route that led me to proficiency in Mandarin Chinese. I am new to programming (working on my Master's of Science in Software Engineering through East Carolina University); however, I will probably always say that about me - there are certainly - at this juncture - those who are going to be "better at it" than me. That said, I am in the game, love it, and think collaboration builds the best code.

Updated on June 04, 2022

Comments

  • Thomas
    Thomas almost 2 years

    I see a pervasive belief (2009 article) throughout the internet that the Hashtable class is not serializable; however, I cannot find any modern documentation that supports this notion.

    The belief stems from another ill-documented belief that the IDictionary interface prevents serialization; however, I cannot find anything in MSDN that supports this claim, today.

    Further, Hashtable implements ISerializable and contains extension methods that accept serialization information.

    So, what's the deal? Is Hashtable serializable? Where is the documentation that supports this notion surrounding IDictionary?

    Further Clarification (please read):

    The statement that IDictionary is not serializable is supported by plenty of documentation; however, this focuses on the use of XML-based serialization interactions with a class. ISerializable as mentioned both in the comments, below, and through MSDN indicates that a class is serializable. It also means the class the must be responsible for its own serialization.

    I think this negates the statement that a Hashtable is not serializable. That is perhaps the genesis of my question.

    • Thomas
      Thomas almost 8 years
      @RobertHarvey sure. That's true. But to say something is plainly not serializable should be supported by documentation, especially if this something extends ISerializable. This seems like a particularly difficult statement to support considering the availability of such libraries as NewtonSoft.
    • Yinda Yin
      Yinda Yin almost 8 years
      It's on this page: "The XmlSerializer cannot process classes implementing the IDictionary interface. This was partly due to schedule constraints and partly due to the fact that a hashtable does not have a counterpart in the XSD type system. The only solution is to implement a custom hashtable that does not implement the IDictionary interface." (Google is a great tool).
    • ManoDestra
      ManoDestra almost 8 years
      As per this article, the reason given is "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.". 2010 article :)
    • James Thorpe
      James Thorpe almost 8 years
      Putting all the talk of serialization aside - it's 2016, why use HashTable at all?
    • Luaan
      Luaan almost 8 years
      One thing to note: .NET hashcodes aren't persistable by contract, they aren't even guaranteed to be the same in two different application domains, IIRC. So serializing a dictionary or a hashtable can only really save the keys and values, and "manually" reconstructing the hash-ness on the target.
    • usr
      usr almost 8 years
      There are many forms of serialization. Some work (BinaryFormatter, Json), some don't (Xml). Is this even relevant in 2016? Don't use the Hashtable class at all.
  • Thomas
    Thomas almost 8 years
    I'm a former Java developer. I am still getting used to the idea (reinforced here) that a lot of people associate the word "serialization" with the XmlSerializer.
  • Luaan
    Luaan almost 8 years
    @Thomas It's funny, because when I was starting with Java, everyone associated Xml with everything in Java :P .NET (and the JVM ecosystem too, of course) is very complex, and it has many different goals. Is it a good idea that some objects can be serialized in one way but not another? It definitely makes things look a lot less abstract and bad OOP, doesn't it? And .NET was heavily marketed around web services and SOAP, so the connection to XML makes a lot of sense. XmlSerializer is very specific in that it's explicitly designed to make good XML; BinaryFormatter has its own format.
  • Thomas
    Thomas almost 8 years
    When I left Java, I was using Spring annotations (which under the hood is XML). I've got a personal dislike of XML (nothing more than distaste). But, as a Java J2EE (again annotations made their way in to cover the XML) and, especially, as a JavaScript engineer, XML and serialization (for me) just aren't as strongly connected. Different generation, maybe?
  • Luaan
    Luaan almost 8 years
    @Thomas Well, I've been working with binary serialization long before I first heard of XML, including the fake-y serialization like "take this whole bunch of in-memory C structs and save it to file all at once". And I still use binary serialization for everything that warrants it. It's just that I really got to like XML - it's a well defined format for interop, and in most of my commercial projects, interop is almost the only place we ever used serialization (and a smattering of hand crafted binary formats where critical). I suspect modern programmers will have a similar thing about JSON :)