2010-03-20 38 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上調用+ =時,就會創建一個新的字符串對象時間和記憶)。雖然不太可能會因此而耗盡內存,但是很長的列表可能會輕易地引發對應用程序性能的影響。

希望這有助於的