如何使用Dictionary 属性序列化对象?

在下面的示例代码中,我收到此错误

Element TestSerializeDictionary123.Customer.CustomProperties vom Typ System.Collections.Generic.Dictionary`2 [[System.String,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089],[System.Object,mscorlib,Version = 2.0 .0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]无法序列化,因为它实现了IDictionary。

当我取出Dictionary属性时,它工作正常

如何使用字典属性序列化此Customer对象? 或者我可以使用哪种替换类型的词典可序列化?

using System; using System.Collections.Generic; using System.Xml.Serialization; using System.IO; using System.Xml; using System.Text; namespace TestSerializeDictionary123 { public class Program { static void Main(string[] args) { List customers = Customer.GetCustomers(); Console.WriteLine("--- Serializing ------------------"); foreach (var customer in customers) { Console.WriteLine("Serializing " + customer.GetFullName() + "..."); string xml = XmlHelpers.SerializeObject(customer); Console.WriteLine(xml); Console.WriteLine("Deserializing ..."); Customer customer2 = XmlHelpers.DeserializeObject(xml); Console.WriteLine(customer2.GetFullName()); Console.WriteLine("---"); } Console.ReadLine(); } } public static class StringHelpers { public static String UTF8ByteArrayToString(Byte[] characters) { UTF8Encoding encoding = new UTF8Encoding(); String constructedString = encoding.GetString(characters); return (constructedString); } public static Byte[] StringToUTF8ByteArray(String pXmlString) { UTF8Encoding encoding = new UTF8Encoding(); Byte[] byteArray = encoding.GetBytes(pXmlString); return byteArray; } } public static class XmlHelpers { public static string SerializeObject(object o) { MemoryStream ms = new MemoryStream(); XmlSerializer xs = new XmlSerializer(typeof(T)); XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); xs.Serialize(xtw, o); ms = (MemoryStream)xtw.BaseStream; return StringHelpers.UTF8ByteArrayToString(ms.ToArray()); } public static T DeserializeObject(string xml) { XmlSerializer xs = new XmlSerializer(typeof(T)); MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml)); XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); return (T)xs.Deserialize(ms); } } public class Customer { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Street { get; set; } public string Location { get; set; } public string ZipCode { get; set; } public Dictionary CustomProperties { get; set; } private int internalValue = 23; public static List GetCustomers() { List customers = new List(); customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" }); customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" }); customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" }); customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" }); customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" }); return customers; } public string GetFullName() { return FirstName + " " + LastName + "(" + internalValue + ")"; } } } 

在我们的应用中,我们最终使用:

 DataContractSerializer xs = new DataContractSerializer(typeof (T)); 

代替:

 XmlSerializer xs = new XmlSerializer(typeof (T)); 

这解决了这个问题,因为DatacontractSerializer支持Dictionary。

另一个解决方案是XML Serializable Generic Dictionary变通方法也适用于上面的示例,并且在使用它的人的链接上进行了长时间的讨论,对于处理此问题的人可能会有用。

这是一个知道如何自行序列化的通用字典类:

  public class XmlDictionary : Dictionary, IXmlSerializable { [XmlType("Entry")] public struct Entry { public Entry(T key, V value) : this() { Key = key; Value = value; } [XmlElement("Key")] public T Key { get; set; } [XmlElement("Value")] public V Value { get; set; } } System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; } void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { this.Clear(); var serializer = new XmlSerializer(typeof(List)); reader.Read(); // Why is this necessary? var list = (List)serializer.Deserialize(reader); foreach (var entry in list) this.Add(entry.Key, entry.Value); reader.ReadEndElement(); } void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { var list = new List(this.Count); foreach (var entry in this) list.Add(new Entry(entry.Key, entry.Value)); XmlSerializer serializer = new XmlSerializer(list.GetType()); serializer.Serialize(writer, list); } } 

你不能(没有自己做,这是可怕的); xml序列化程序不会知道如何处理object ,因为它不包括有线格式的类型元数据。 一个(hacky)选项是将这些全部作为字符串流式传输以用于序列化,但是您需要编写大量额外的解析(等)代码。

您可以使用二进制序列化 。 (只需确保所有类都标记为[Serializable] 。当然,它不是XML格式,但你没有将其列为要求:)

我刚刚发现Rakesh Rajan的这篇博客文章描述了一个可能的解决方案:

通过使类型实现System.Xml.Serialization.IXmlSerializable类来覆盖XmlSerialization。 在WriteXml方法中定义如何在XML中序列化对象,并定义如何从ReadXml方法中的xml字符串重新创建对象。

但是这不起作用,因为您的Dictionary包含object而不是特定类型。

如何将Customer类标记为DataContract,将其属性标记为DataMembers。 DataContract序列化器将为您进行序列化。

尝试通过BinaryFormatter进行序列化

 private void Deserialize() { try { var f_fileStream = File.OpenRead(@"dictionarySerialized.xml"); var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); myDictionary = (Dictionary)f_binaryFormatter.Deserialize(f_fileStream); f_fileStream.Close(); } catch (Exception ex) { ; } } private void Serialize() { try { var f_fileStream = new FileStream(@"dictionarySerialized.xml", FileMode.Create, FileAccess.Write); var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); f_binaryFormatter.Serialize(f_fileStream, myDictionary); f_fileStream.Close(); } catch (Exception ex) { ; } }