我在整个互联网上看到普遍的belief(2009年文章),Hashtable
类不可序列化;但是,我找不到任何支持这个概念的现代文档。
这种信念源于另一个记录不明的信念,即IDictionary
界面阻止序列化;但是,我今天在MSDN中找不到支持此声明的任何内容。
此外,Hashtable
实现ISerializable
并包含接受序列化信息的扩展方法。
那么,这笔交易是什么? Hashtable
是否可序列化?支持围绕IDictionary
的概念的文档在哪里?
进一步澄清(请阅读):
大量文档支持IDictionary
不可序列化的声明;但是,这侧重于使用基于XML的序列化与类的交互。如下面的注释和MSDN中所提到的ISerializable
表示类是可序列化的。它还意味着必须负责其自身序列化的类。
我认为这否定了Hashtable不可序列化的说法。这可能是我的问题的起源。
答案 0 :(得分:6)
普遍的信念是如此普遍,因为它是真的:
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类会抛出错误。”
答案 1 :(得分:5)
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.NotSupportedException'的例外情况发生在System.Xml.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序列化提到您无法序列化未签名的long或集合。
答案 2 :(得分:1)
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);
}
}
}