37

I have a list of key/value pairs I'd like to store in and retrieve from a XML file. So this task is similar as described here. I am trying to follow the advice in the marked answer (using a KeyValuePair and a XmlSerializer) but I don't get it working.

What I have so far is a "Settings" class ...

public class Settings
{
    public int simpleValue;
    public List<KeyValuePair<string, int>> list;
}

... an instance of this class ...

Settings aSettings = new Settings();

aSettings.simpleValue = 2;

aSettings.list = new List<KeyValuePair<string, int>>();
aSettings.list.Add(new KeyValuePair<string, int>("m1", 1));
aSettings.list.Add(new KeyValuePair<string, int>("m2", 2));

... and the following code to write that instance to a XML file:

XmlSerializer serializer = new XmlSerializer(typeof(Settings));
TextWriter writer = new StreamWriter("c:\\testfile.xml");
serializer.Serialize(writer, aSettings);
writer.Close();

The resulting file is:

<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <simpleValue>2</simpleValue>
  <list>
    <KeyValuePairOfStringInt32 />
    <KeyValuePairOfStringInt32 />
  </list>
</Settings>

So neither key nor value of the pairs in my list are stored though the number of elements is correct. Obviously I am doing something basically wrong. My questions are:

  • How can I store the key/value pairs of the list in the file?
  • How can I change the default generated name "KeyValuePairOfStringInt32" of the elements in the list to some other name like "listElement" I'd like to have?
Community
  • 1
  • 1
Slauma
  • 175,098
  • 59
  • 401
  • 420

1 Answers1

68

KeyValuePair is not serializable, because it has read-only properties. Here is more information(thanks to Thomas Levesque). For changing the generated name use the [XmlType] attribute.

Define your own like this:

[Serializable]
[XmlType(TypeName="WhateverNameYouLike")]
public struct KeyValuePair<K, V>
{
  public K Key 
  { get; set; }

  public V Value 
  { get; set; }
}
Petar Minchev
  • 46,889
  • 11
  • 103
  • 119
  • 4
    Great, it works, thank you! I've added a constructor to your struct: `public KeyValuePair(K k, V v) : this() { Key = k; Value = v; }`, so I can use my code to fill the list without changes. Also I figured out that as an alternative to `[XmlType]` I can decorate the list in the Settings class with `[XmlArrayItem(ElementName="WhateverNameYouLike")]`. It can be useful if I had two lists of `KeyValuePair` but want to give the elements different names in the XML file. Thanks again! – Slauma Apr 17 '10 at 16:32
  • 7
    It has nothing to do with the `Serializable` attribute : XML serialization doesn't need it. The reason is that the `Key` and `Value` properties are read-only – Thomas Levesque Apr 17 '10 at 17:48
  • @Thomas, Wow thanks. You are right - http://blogs.msdn.com/seshadripv/archive/2005/11/02/488273.aspx – Petar Minchev Apr 17 '10 at 18:15
  • @Thomas: Thanks for explanation! Yes, I've removed the `[Serializable]` attribute and it still works. Does that generally mean that only read/write properties (and public members?) can be Xml-serialized? Edit: Petar's link already answered the question :) – Slauma Apr 17 '10 at 18:15
  • 2
    Just to mention: The `[XmlType]` attribute applied to the class template turned out to be a problem when I have two lists of different types of KeyValuePair in my Settings class, for instance a `List>` and a `List>`. Then the constructor of XmlSerializer throws an exception and complains that I have the same XML-TypeName for two different types which seems to be forbidden. For now I have removed the XmlType attribute and applied `[XmlArrayItem...]` directly to the list members as mentioned in my first comment. – Slauma Apr 17 '10 at 18:43
  • 1
    Thanks, That helped me alot, i was having the same problem. +1 for you – Marcello Grechi Lins May 21 '13 at 13:20
  • 1
    "KeyValuePair is not serializable, because it has read-only properties" is incorrect. Yes that it's not XML serialisable, yes that it has read only properties, but NO not BECAUSE. The two statements are not cause and effect. One fundamental reason is that the XML Serialiser DOES NOT READ THE VALUES (check the output stream, dudes), even though they are read-properties! Note that KeyValuePair is (de)serialisable via Binary and JSON – brewmanz Apr 09 '19 at 21:59