Hashtables是否可序列化?

我在互联网上看到了一个普遍的信念 (2009年文章), Hashtable类不可序列化; 但是,我找不到任何支持这个概念的现代文档。

这种信念源于另一个不明确的信念,即IDictionary接口阻止序列化; 但是,我今天在MSDN中找不到任何支持此声明的内容。

此外, Hashtable实现了ISerializable并包含接受序列化信息的扩展方法。

那么,这笔交易是什么? Hashtable是否可序列化? 哪些文档支持围绕IDictionary概念?

进一步澄清请阅读 ):

大量文档支持IDictionary不可序列化的声明; 但是,这侧重于使用基于XML的序列化与类的交互。 如下面的注释和MSDN中所提到的ISerializable表示类是可序列化的。 它还意味着必须为自己的序列化负责的类。

我认为这否定了Hashtable不可序列化的说法。 这可能是我的问题的起源。

普遍的信念是如此普遍,因为它是真的:

 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()); } 

NotSupportedException:不支持System.Collections.Hashtable类型,因为它实现了IDictionary。

这并不意味着序列化哈希表几乎是不可能的 。 当然,我可以迭代所有键和值,将它们写入字符串,然后从中重构哈希表。 只是我不能完全使用序列化基础设施。

这是什么原因? 它实际上非常简单–XmlSerializer旨在生成良好的XML,本着XML的交换格式的精神设计。 并且XML没有任何适合的字典或“键值”机制。 因此,为了支持哈希表序列化,他们必须使用自己的规则制作自己的“子格式”。 回到.NET设计时,这是一个巨大的禁忌 – XML是一种交换格式。 对格式的任何扩展(hah)意味着你不再兼容,无论你有多么好的想法。

当然,现在,每个人和他们的祖母都在生成不用于交换目的的XML数据。 并不是一件坏事(毕竟,.NET config文件也是一种XML格式)。 但它也有点不对劲。

相反,采取BinaryFormatter东西。 这是.NET团队设计整个格式的类,不受标准限制。 而且看到 – BinaryFormatter可以序列化和反序列化Hashtable就好了。

因此,稍微更正确的信念是“Hashtable无法序列化为有效的标准XML。特别是当您尝试序列化Hashtable时,XmlSerializer类会抛出错误。”

Hashtable是否实现了ISerializable? 绝对:

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

我们可以将Hashtable序列化为XML吗? 我们来试试吧:

  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); 

结果…错误如您所料

System.Xml.dll中发生类型为“System.NotSupportedException”的exception,但未在用户代码中处理

附加信息:不支持System.Collections.Hashtable类型,因为它实现了IDictionary。

所以,看起来确实如此,在.Net 4.5+中仍然如此

但让我们再试一次二进制序列化……

  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(); 

结果…没有抛出错误… 所以问题似乎与IDictionary和XmlSerialization有关,但不是所有序列化

如果你真的需要对XML做这个,ManoDestra有一个很好的链接https://blogs.msdn.microsoft.com/adam/2010/09/10/how-to-serialize-a-dictionary-or-hashtable-in -C/

另外,有趣的是,XML序列化提到您无法序列化未签名的long或集合。

Microsoft XML序列化(MSDN)

微软似乎表示肯定可以这样做。 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); } } 

}