C# 反序列化集合时未调用Setter

C# 反序列化集合时未调用Setter,c#,collections,setter,xmlserializer,C#,Collections,Setter,Xmlserializer,我正在尝试使用XmlSerializer进行一个非常简单的序列化: public struct XmlPerson { [XmlAttribute] public string Id { get; set; } [XmlAttribute] public string Name { get; set; } } public class GroupOfPeople { private Dictionary<string, string> _namesByI

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

您是否尝试过使用XmlArray属性

以您的示例为例,可能是这样的:

[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople
[XmlArray]
[XmlArrayItem(ElementName=“XmlPerson”)]
公众人物名单
编辑:

在这里,请尝试以下结构:

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; }
}
public结构XmlPerson
{
[XmlAttribute]公共字符串Id{get;set;}
[XmlAttribute]公共字符串名称{get;set;}
}
公共阶层人群
{
[XmlArray]
[XmlArrayItem(ElementName=“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;
    }
}
private Dictionary\u namesById;
公共字典namebyid
{
设置{u namesById=value;}
得到
{
if(_namesById==null)
{
_namesById=newdictionary();
foreach(XmlPeople中的var人员)
{
_namesById.Add(person.Id,person.Name);
}
}
返回_namesById;
}
}
通过这种方式,您可以从XML中获取项目,还可以保存您的字典。

为了清晰起见,请回答:

已经进行了一些调试,发现
XmlSerializer
没有为集合调用setter。


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

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

这不适用于反序列化,原因已在中指出。 (反序列化调用getter,然后将元素添加到它返回的“临时”集合中,然后丢弃该集合)

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

(在下面的代码中,“实际收集”是
\u nameById
MyItem
XmlPerson

公共类MyProxyCollection:IList{
MyProxyCollection(…/*对实际集合的引用*/…){…}
//在这里实现IList
}
公共类MyModel{
MyProxyCollection\u代理;
公共MyModel(){
_代理=新的MyProxyCollection(…/*对实际集合的引用*/…);
}
//在这里,我们确保getter和setter始终返回对同一对象的引用
//集合对象。这确保我们将项添加到上的正确集合
//反序列化。
公共MyProxyCollection项{get;set;}
}

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

从不调用setter。我有一个断点在上面。保存时可以明显识别属性,但仍无法加载:/@GazTheDestroyer编辑了答案以包含一些代码示例。正在进行一些调试(请参见我的答案),但已将您的答案设置为正确,因为它确实解决了问题。把我的答案写清楚,以防其他人有问题。
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; }
}
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;
    }
}
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;}
}