6

我正在尝试使用 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 属性设置器永远不会被调用,因此字典是空的。此对象上的所有其他属性都可以正常反序列化。

我错过了一些明显的东西吗?我尝试了各种集合类型,但都没有反序列化。

编辑:阅读代码:

try
{
    using (var stream = new StreamReader(itemPath))
    {
        var xml = new XmlSerializer(typeof(GroupOfPeople));
        GroupOfPeople item = (GroupOfPeople)xml.Deserialize(stream);  
    }  
}
//snip error stuff
4

3 回答 3

17

为了清楚起见,回答:

做了一些调试,发现XmlSerializer没有为集合调用setter。

而是调用getter,然后将项目添加到返回的集合中。因此,需要像 Felipe 那样的解决方案。

于 2012-04-23T15:30:33.700 回答
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 并不容易,那么当您真正需要它时获取该 Dictionary 怎么样?

像这样:

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 中获取项目,并且还将维护您的字典。

于 2012-04-23T14:07:41.367 回答
0

在这个问题中,该_XmlPeople属性充当_namesById字典的“代理”,即实际存储集合元素的位置。它的 getter 和 setter 在不同类型的集合之间转换。

这不适用于反序列化,原因在https://stackoverflow.com/a/10283576/2279059中指出。(反序列化调用getter,然后将元素添加到它返回的“临时”集合中,然后将其丢弃)。

一个通用的解决方案是将“代理集合”实现为一个单独的类,然后拥有一个作为代理集合的属性:

(在下面的代码中,“实际集合”是_nameById,并且MyItemXmlPerson

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;}
}

这可确保获取/设置集合对象按预期工作。

于 2019-01-23T14:15:00.313 回答