【问题标题】:Setter not called when deserializing collection反序列化集合时未调用 Setter
【发布时间】:2019-01-23 22:15:00
【问题描述】:

我正在尝试使用 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

【问题讨论】:

  • setter 永远不会被调用。我有一个断点。

标签: c# collections setter xmlserializer


【解决方案1】:

为了清楚起见回答:

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

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

【讨论】:

    【解决方案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 中获取项目,并且还可以维护您的字典。

    【讨论】:

    • 不。保存时属性明显识别,但仍然没有加载。 ://
    • @GazTheDestroyer 编辑了答案以包含一些代码示例。
    • 一直在进行一些调试(请参阅我的答案),但已将您的答案设置为正确,因为它确实解决了问题。请把我的答案说清楚,以防其他人有问题。
    【解决方案3】:

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

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

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

    (在下面的代码中,“实际集合”为_nameByIdMyItemXmlPerson

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多