设置:
class Item
{
private int _value;
public Item()
{
_value = 0;
}
public int Value { get { return _value; } set { _value = value; } }
}
class ItemCollection : Collection<Item>
{
private string _name;
public ItemCollection()
{
_name = string.Empty;
}
public string Name { get {return _name;} set {_name = value;} }
}
现在,尝试使用以下代码片段进行序列化:
ItemCollection items = new ItemCollection();
...
XmlSerializer serializer = new XmlSerializer(typeof(ItemCollection));
using (FileStream f = File.Create(fileName))
serializer.Serialize(f, items);
查看生成的XML后,我看到ItemCollection.Name值不存在!
我认为可能发生的事情是序列化程序将ItemCollection类型视为一个简单的集合,因此忽略了任何其他添加的属性......
是否有人遇到过这样的问题并找到了解决方案?
此致
Stécy
答案 0 :(得分:12)
此行为是“按设计”。从集合类派生时,Xml Seralizier将仅序列化集合元素。要解决这个问题,您应该创建一个封装集合和名称的类,并将其序列化。
class Wrapper
{
private Collection<Item> _items;
private string _name;
public Collection<Item> Items { get {return _items; } set { _items = value; } }
public string Name { get { return _name; } set { _name = value; } }
}
答案 1 :(得分:4)
XmlSerializer是邪恶的。也就是说,任何实现IEnumerable的对象都会被序列化为一个简单的集合,忽略你自己添加的任何额外属性。
您需要创建一个包含属性和返回集合的属性的新类。
答案 2 :(得分:2)
我不确定我是否遗漏了某些内容,但您希望生成的xml是
吗?<ItemCollection>
<Name>name val</Name>
<Item>
<Value>1</alue>
</Item
<Item>
<Value>2</alue>
</Item
</ItemCollection>
如果是这样,只需将XmlRoot属性应用于itemcollection类并设置元素名称......
[XmlRoot(ElementName="ItemCollection")]
public class ItemCollection : Collection<Item>
{
[XmlElement(ElementName="Name")]
public string Name {get;set;}
}
这将指示序列化程序为您的集合容器输出所需的名称。
答案 3 :(得分:0)
您还可以尝试使用IXmlSerializable接口
实现自己的序列化 public class ItemCollection : Collection<Item>,IXmlSerializable
{
private string _name;
public ItemCollection()
{
_name = string.Empty;
}
public string Name
{
get { return _name; }
set { _name = value; }
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("name", _name);
List<Item> coll = new List<Item>(this.Items);
XmlSerializer serializer = new XmlSerializer(coll.GetType());
serializer.Serialize(writer, coll);
}
#endregion
}
上面的代码将生成序列化的xml为
<?xml version="1.0"?>
<ItemCollection>
<name />
<ArrayOfItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Item>
<Value>1</Value>
</Item>
<Item>
<Value>2</Value>
</Item>
</ArrayOfItem>
</ItemCollection>
答案 4 :(得分:0)
public class Animals : List<Animal>, IXmlSerializable
{
private static Type[] _animalTypes;//for IXmlSerializable
public Animals()
{
_animalTypes = GetAnimalTypes().ToArray();//for IXmlSerializable
}
// this static make you access to the same Animals instance in any other class.
private static Animals _animals = new Animals();
public static Animals animals
{
get {return _animals; }
set { _animals = value; }
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
reader.MoveToContent();
reader.ReadStartElement("Animals");
// you MUST deserialize with 'List<Animal>', if Animals class has no 'List<Animal>' fields but has been derived from 'List<Animal>'.
List<Animal> coll = GenericSerializer.Deserialize<List<Animal>>(reader, _animalTypes);
// And then, You can set 'Animals' to 'List<Animal>'.
_animals.AddRange(coll);
reader.ReadEndElement();
//Read Closing Element
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteStartElement("Animals");
// You change 'List<Animal>' to 'Animals' at first.
List<Animal> coll = new List<Animal>(_animals);
// And then, You can serialize 'Animals' with 'List<Animal>'.
GenericSerializer.Serialize<List<Animal>>(coll, writer, _animalTypes);
writer.WriteEndElement();
}
#endregion
public static List<Type> GetAnimalTypes()
{
List<Type> types = new List<Type>();
Assembly asm = typeof(Animals).Assembly;
Type tAnimal = typeof(Animal);
//Query our types. We could also load any other assemblies and
//query them for any types that inherit from Animal
foreach (Type currType in asm.GetTypes())
{
if (!currType.IsAbstract
&& !currType.IsInterface
&& tAnimal.IsAssignableFrom(currType))
types.Add(currType);
}
return types;
}
}