在摘要:
一些.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上調用+ =時,就會創建一個新的字符串對象時間和記憶)。雖然不太可能會因此而耗盡內存,但是很長的列表可能會輕易地引發對應用程序性能的影響。
希望這有助於的
可能重複[如何將XML序列化的LinkedList?](http://stackoverflow.com/questions/2271582/how-to-xml-serialize-a-linkedlist) – nawfal 2014-07-16 21:46:13