哈希表是否可序列化

本文关键字:序列化 是否 哈希表 | 更新日期: 2023-09-27 17:56:51

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

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

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

那么,这是怎么回事呢?Hashtable可序列化吗?支持围绕IDictionary的概念的文档在哪里?

进一步澄清请阅读):

大量文档支持IDictionary不可序列化的语句;但是,这侧重于使用基于 XML 的序列化与类的交互。 ISerializable如下面的注释中所述,以及通过 MSDN 表示类是可序列化的。这也意味着类必须负责自己的序列化。

我认为这否定了哈希表不可序列化的说法。这也许就是我问题的起源。

哈希表是否可序列化

普遍

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

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 是一种交换格式。格式的任何扩展(哈)都意味着您不再兼容,无论您的想法有多好。

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

相比之下,采取类似 BinaryFormatter .这是 .NET 团队设计整个格式的类,不受标准限制。你瞧 - BinaryFormatter可以序列化和反序列化Hashtable就可以了。

因此,稍微正确的信念是"哈希表不能序列化为有效的标准XML。特别是 XmlSerializer 类会在您尝试序列化哈希表时引发错误。

哈希表是否实现了 ISerializable? 绝对:

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

我们可以将哈希表序列化为 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 中发生类型为"System.NotSupportedException"的异常.dll但未在用户代码中处理

其他信息:不支持 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 序列化提到不能序列化无符号长整型或其集合。

Microsoft XML 序列化 (MSDN)

Microsoft似乎在说这样做当然是可能的。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);
    }
}
}