以下是我的课程:http://pastebin.com/3dc5Vb1t
当我尝试运行时
BookStore b = new BookStore();
b.LoadFromXML(Server.MapPath("list.xml"));
Label1.Text = b.ToString();
我收到以下错误:
您必须在System.Collections.Generic.LinkedList`1 [[Book,App_Code.cxsacizw,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null]]上实现默认访问器,因为它继承自ICollection。
错误来源为XmlSerializer s = new XmlSerializer(typeof(BookStore));
当我试图在谷歌上寻找解决方案时,我发现LinkedList在序列化方面存在一些问题。我该如何处理?
非常感谢。
答案 0 :(得分:5)
似乎不可能。
此处有错误报告:linkedlist-t-can-not-be-serialized-using-the-xmlserializer。在哪里可以阅读以下内容:
微软于11/11/2004发表于 19时35分强>
我们选择不拥有索引器 LinkedList上的方法用于表现 原因。所以LinkedList不会 XMLSeriliazable。
答案 1 :(得分:4)
摘要:
某些.Net类型(如链接列表,哈希表(字典)等)在尝试序列化时会出现一些问题。这似乎主要是设计的:还有其他更简单的类型可以表示相同的值范围(例如,普通列表而不是链表,或者是对的列表而不是字典),所以.Net假定如果您使用的是更具体的类型,则需要其特定功能。如果无法序列化此类功能(例如,无法在XML中对哈希表进行描述),则会出现问题。
关键点在于:您是否真的需要在序列化表单上使用这些类型的特定功能?例如,如果您序列化链表以使序列化版本包含元素之间的链接,那么您将会遇到严重的问题。幸运的是,在大多数情况下,在实际使用对象时只需要特殊功能,因此可以序列化它的简化(但足够完整)版本,并在反序列化时重建高级对象。
为了实现上述目标,.Net包含了一些有用的工具来干预de /序列化过程。首先,您应该始终使用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”参数,都必须是可序列化的,但无法在代码中强制执行此类要求。
顺便说一句,让我处理一些合法的事情:作为上面代码段的作者,我授予任何人不得撤销的,非独占的全球许可,以便将其用于任何目的(包括但不是限制,创造任何形式的衍生作品,并以任何形式分发它们。归档不是必需的,但总是受欢迎。
哦,看了你的代码之后,我强烈建议你使用StringBuilder来实现你的ToString()方法:每次你的代码在String上调用+ =时,就会创建一个新的字符串对象(需要时间)和记忆)。虽然您不太可能因此而耗尽内存,但很长的列表可能很容易对您的应用程序产生性能影响。
希望这有帮助
答案 2 :(得分:3)
请参阅When should I use a List vs a LinkedList
如果您使用链接列表,可能会因为性能原因而假设您这样做。否则,列表&lt; T&gt;可能更合适。