我试图用XmlSerializer做一个非常简单的序列化:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
private Dictionary<string, string> _namesById = new Dictionary<string, string>();
//pseudo property for serialising dictionary to/from XML
public List<XmlPerson> _XmlPeople
{
get
{
var people = new List<XmlPerson>();
foreach (KeyValuePair<string, string> pair in _namesById )
people.Add(new XmlPerson() { Id = pair.Key, Name = pair.Value });
return people;
}
set
{
_namesById.Clear();
foreach (var person in value)
_namesById.Add(person.Id, person.Name);
}
}
}
保存此类工作正常,我得到:
<?xml version="1.0" encoding="utf-8"?>
<GroupOfPeople xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<_XmlPeople>
<XmlPerson Id="person1" Name="Fred" />
<XmlPerson Id="person2" Name="Bill" />
<XmlPerson Id="person3" Name="Andy" />
<XmlPerson Id="person4" Name="Nagesh" />
</_XmlPeople>
</GroupOfPeople>
但是,当我再次读入文件时,我的_XmlPeople属性setter永远不会被调用,因此字典为空。此对象上的所有其他属性都可以反序列化。
我错过了一些明显的东西吗?我尝试了各种集合类型,但没有一个反序列化。
编辑:阅读代码:
try
{
using (var stream = new StreamReader(itemPath))
{
var xml = new XmlSerializer(typeof(GroupOfPeople));
GroupOfPeople item = (GroupOfPeople)xml.Deserialize(stream);
}
}
//snip error stuff
答案 0 :(得分:15)
澄清答案:
进行了一些调试,发现 XmlSerializer
没有为集合调用setter。
而是调用 getter ,然后将项添加到返回的集合中。因此,像费利佩这样的解决方案是必要的。
答案 1 :(得分:2)
您是否尝试过使用XmlArray属性?
用你的例子可能是这样的:
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople
修改强>
在这里,尝试以下结构:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople { get; set; }
}
我认为将代码添加到列表的Setter中并不容易,那么在实际需要时获取该词典呢?
像这样:
private Dictionary<string, string> _namesById;
public Dictionary<string, string> NamesById
{
set { _namesById = value; }
get
{
if (_namesById == null)
{
_namesById = new Dictionary<string, string>();
foreach (var person in XmlPeople)
{
_namesById.Add(person.Id, person.Name);
}
}
return _namesById;
}
}
这样你就可以从XML中获取这些项目,并且也会保留你的词典。
答案 2 :(得分:0)
在此问题中,_XmlPeople
属性用作_namesById
字典的“代理”,该字典实际上是存储集合元素的位置。它的获取器和设置器在不同类型的集合之间进行转换。
这不适用于反序列化,其原因在https://stackoverflow.com/a/10283576/2279059中指出。 (反序列化调用 getter ,然后将元素添加到它返回的“临时”集合中,然后将其丢弃)。
一个通用的解决方案是将“代理集合”实现为一个单独的类,然后具有一个作为代理集合的属性:
(在下面的代码中,“实际集合”为_nameById
,而MyItem
为XmlPerson
)
public class MyProxyCollection : IList<MyItem> {
MyProxyCollection(... /* reference to actual collection */ ...) {...}
// Implement IList here
}
public class MyModel {
MyProxyCollection _proxy;
public MyModel() {
_proxy = new MyProxyCollection (... /* reference to actual collection */ ...);
}
// Here we make sure the getter and setter always return a reference to the same
// collection object. This ensures that we add items to the correct collection on
// deserialization.
public MyProxyCollection Items {get; set;}
}
这确保获取/设置集合对象可以按预期工作。