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、コレクションのセッターを呼び出さないことがわかりました。

代わりに、 getterを呼び出してから、返されたコレクションにアイテムを追加します。したがって、フェリペのような解決策が必要です。

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

リストのセッターにコードを追加するのは簡単ではないと思います。実際に必要なときにその辞書を取得するのはどうでしょうか。

このような:

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そのゲッターとセッターは、異なるタイプのコレクション間で変換します。

これは逆シリアル化では機能しません。理由は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;}
}

これにより、コレクションオブジェクトの取得/設定が期待どおりに機能することが保証されます。

于 2019-01-23T14:15:00.313 に答える