2010-03-20 82 views
3

这里是我的课:http://pastebin.com/3dc5Vb1tLinkedList无法序列化?

当我尝试运行

BookStore b = new BookStore(); 
b.LoadFromXML(Server.MapPath("list.xml")); 
Label1.Text = b.ToString(); 

我收到以下错误:

You must implement a default accessor on System.Collections.Generic.LinkedList`1[[Book, App_Code.cxsacizw, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] because it inherits from ICollection.

的误差源是XmlSerializer s = new XmlSerializer(typeof(BookStore));

当我试图在google上寻找解决方案,我发现LinkedList在序列化方面存在一些问题。我该如何处理它?

非常感谢。

+0

可能重复[如何将XML序列化的LinkedList?](http://stackoverflow.com/questions/2271582/how-to-xml-serialize-a-linkedlist) – nawfal 2014-07-16 21:46:13

回答

5

看来这是不可能的。

Bug report here:linkedlist-t-can-not-be-serialized-using-the-xmlserializer。在这里你可以阅读以下内容:

Posted by Microsoft on 11/11/2004 at 19:35
We chose not to have a indexer method on LinkedList for performance reason. So LinkedList will not be XMLSeriliazable.

+0

如果是这样, 我能做什么?我不想使用数组,因为我不确定数组中包含多少项。 – iTayb 2010-03-20 14:14:54

+1

您使用列表http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx – kervin 2010-03-20 14:17:50

4

在摘要:

一些.NET类型如链表,哈希表(字典)等有一些问题,当您尝试序列化。这似乎主要是通过设计:还有其他更简单的类型可以表示相同的值范围(例如,普通列表而不是链接列表,或者对的列表而不是字典),所以.Net假定如果您使用更具体的类型,则需要其特定功能。当这些功能无法序列化时(例如,不能用XML描述散列表),就会出现问题。

重点是:你真的需要这些类型的特定功能在他们的序列化的形式?例如,如果您要序列化一个链表,以便序列化版本包含元素之间的链接,那么您将会遇到严重的麻烦。幸运的是,在大多数情况下,只有在实际使用该对象时才需要特殊功能,因此您可以序列化一个简化的(但完整的)版本并在反序列化时重建高级对象。

为了实现上述可能性,.Net包含一些有用的工具来干涉反序列化过程。首先,您应该始终用System.SerializableAttribute(http://msdn.microsoft.com/en-us/library/system.serializableattribute.aspx)标记可序列化对象。接下来,您可以实现System.Runtime.Serialization.ISerializable(http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx)以完全控制序列化过程。在最简单的情况下,你需要做的就是将你的链表转换成普通的链表,并将它添加到你在GetObjectData(...)中得到的SerializationInfo参数作为一个单一值(我假设你将它标记为“值“)进行序列化。然后,要启用反序列化,请添加如下例所示的构造函数。

但是,这仅涵盖共享序列化基础结构。要完全控制XML序列化,您需要实现System.Xml.Serialization.IXmlSerializable。这样做时,请记住,编写器会隐式地将输出封装在表示被序列化的对象类型的元素中;读者需要明确地挖掘该元素(在某些情况下,可能需要此不对称)。如果你不习惯,实现这个接口可能会很棘手。Net的XML流;但幸运的是,我不得不在前一段时间对字典做类似的事情,并且我可以回收大部分代码;)。

具体到: 本示例提供LinkedList序列化为“普通”列表的基本要素,并将其反序列化回链接列表。序列化表格不是包含元素间链接;但这些链接在反序列化后可靠地重新制作。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml.Serialization; 
using System.Runtime.Serialization; 
using System.Xml; 
using System.IO; 

namespace WFTest { 
    [Serializable] 
    class SerializableLinkedList<T>: LinkedList<T>, ISerializable, IXmlSerializable { 
     void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { 
      info.AddValue("value", this.ToList()); 
     } 
     // Implied by ISerializable, but interfaces can't actually define constructors: 
     SerializableLinkedList(SerializationInfo info, StreamingContext context) 
      : base((IEnumerable<T>)info.GetValue("value", typeof(List<T>))) { } 

     System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; } 

     void IXmlSerializable.ReadXml(XmlReader reader) { 
      this.Clear(); // Start with an empty list 
      reader.ReadStartElement(); // Skips the opening tag 
      while (reader.LocalName=="item") { // Retrieve all elements: 
       T value; 
       if(reader.IsEmptyElement) { // If element is empty... 
        value=default(T); // the item's value falls back to default(T) 
        reader.ReadStartElement(); // and consume the (empty) element 
       } else { 
        // IIRC, ReadInnerXml() consumes the outer tag, despite not returning them. 
        value=(T)((new XmlSerializer(typeof(T))).Deserialize(new StringReader(reader.ReadInnerXml()))); 
       } 
       this.AddLast(value); 
      } 
      reader.ReadEndElement(); // Consumes the remaining closing tag from the reader 
     } 

     void IXmlSerializable.WriteXml(XmlWriter writer) { 
      foreach(T item in this) { 
       // Format the item itself: 
       StringBuilder sb=new StringBuilder(); 
       (new XmlSerializer(typeof(T))).Serialize(XmlWriter.Create(sb), item); 
       XmlDocument doc=new XmlDocument(); 
       doc.LoadXml(sb.ToString()); 
       // and now write it to the stream within <item>...</item> tags 
       writer.WriteStartElement("item"); 
       writer.WriteRaw(doc.DocumentElement.OuterXml); 
       writer.WriteEndElement(); // </item> 
      } 
     } 
    } 
} 

使用这个类,而不是为对象的“原始” LinkedList类(或基类,如果你需要从LinkedList的派生),和系列化不应触发与列表任何更多的问题。但是,请注意,无论您用作此列表的“T”参数,它们本身都必须是可序列化的,但无法在代码中强制执行此类要求。作为上述代码片段的作者,我授予任何人以任何目的使用它的不可撤销的,非排他性的全球许可,包括但不限于不限于创作任何形式的衍生作品,并以任何形式发布)。归因不是必需的,但总是受欢迎的。

呵呵,看看你的代码后,我强烈建议你为你的ToString()方法的实现使用StringBuilder:每当你的代码在String上调用+ =时,就会创建一个新的字符串对象时间和记忆)。虽然不太可能会因此而耗尽内存,但是很长的列表可能会轻易地引发对应用程序性能的影响。

希望这有助于的