简体   繁体   中英

C# Can't get my dictionary to serialize in XML

I am working on a small project to learn how to serialize an object in C#.NET I created the following class that is the class I am attempting to serialize:

public class Object
{
    private Dictionary<string, int> dictionaryStringInt;

    public Object()
    {
        this.dictionaryStringInt = new Dictionary<string, int>();
    }

    public void AddToDictionary(string s, int i)
    {
        this.dictionaryStringInt.Add(s, i);
    }

    public List<DictionaryEntry> DictionaryStringInt
    {
        get
        {
            List<DictionaryEntry> list = new List<DictionaryEntry>();
            foreach (KeyValuePair<string, int> element in dictionaryStringInt)
            {
                list.Add(new DictionaryEntry(element.Key, element.Value));
            }
            return list;
        }

        set
        {
            Dictionary<string, int> dictionary = new Dictionary<string, int>();
            foreach (DictionaryEntry entry in value)
            {
                dictionary.Add(entry.Key, entry.Value);
            }

            dictionaryStringInt = dictionary;
        }
    }

    public class DictionaryEntry
    {
        private string key;
        private int value;

        public DictionaryEntry()
        {
            this.key = string.Empty;
            this.value = 0;
        }

        public DictionaryEntry(string key, int value)
        {
            this.key = key;
            this.value = value;
        }

        [XmlAttribute("Key")]
        public string Key
        {
            get
            {
                return key;
            }

            set
            {
                key = value;
            }
        }

        [XmlText]
        public int Value
        {
            get
            {
                return value;
            }

            set
            {
                this.value = value;
            }
        }
    }
}

And I have this code here that does the work:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.ClearTextBox();
        SerialisationTest.Object @object = this.SetUpObject();
        this.Serialize(@object);
        @object = null;
        @object = this.Deserialise(@"C:\Sources\SerialisationTest\test.xml");
        this.textBox1.Text = @object.ToString();
        this.DisplayXML(@object);
    }

    public void Serialize(SerialisationTest.Object @object)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
        using (TextWriter writer = new StreamWriter(@"C:\Sources\SerialisationTest\test.xml"))
        {
            serializer.Serialize(writer, @object);
        }
    }

    public SerialisationTest.Object Deserialise(string path)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
        using (TextReader reader = new StreamReader(path))
        {
            return (SerialisationTest.Object)serializer.Deserialize(reader);
        }
    }

    public void DisplayXML(SerialisationTest.Object @object)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(SerialisationTest.Object));
        using (StringWriter writer = new StringWriter())
        {
            serializer.Serialize(writer, @object);
            this.textBox1.Text = writer.ToString();
        }
    }

    public SerialisationTest.Object SetUpObject()
    {
        SerialisationTest.Object @object = new SerialisationTest.Object();

        @object.AddToDictionary("1", 1);
        @object.AddToDictionary("2", 2);
        @object.AddToDictionary("3", 3);

        return @object;
    }

    public void ClearTextBox()
    {
        this.textBox1.Text = "";
    }
}

Now here is the result I see in my textbox:

<?xml version="1.0" encoding="utf-16"?>
<Object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <DictionaryStringInt />
</Object>

Now most of the code is just me playing around trying to serialize things. But then I tried serializing the DictionaryStringInt and saw on MSDN that Dictionary cannot be serialize. So I tried to cheat the serializer by having the property return a list of DictionaryEntry and converting this list into a dictionary in the setter. But as you can see, the DictionaryStringInt 's data is not serialized. I was hoping to received something like:

<?xml version="1.0" encoding="utf-16"?>
<Object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <DictionaryStringInt>
        <DictionaryEntry Key="1">1</DictionaryEntry>
        <DictionaryEntry Key="2">2</DictionaryEntry>
        <DictionaryEntry Key="3">3</DictionaryEntry>
    </DictionaryStringInt>
</Object> 

Does anyone know how to achieve this? (BTW I am aware that if I have multiple of the same key in the XML when deserializing the dictionary I'll get something like an KeyAlreadyPresentException of some sort and this is a behavior want)

Thanks!


Edit

I just found out that the "C:\\Sources\\SerialisationTest\\test.xml" contains the right result.

So there seems to be a problem with the deserialisation or the displaying of the serialisation using the StringWriter.

Is there something I am doing wrong?


Edit2

Simplified the code


Edit3

I looked at the answer linked in the comment and I think I got what is going on... In one of the answers there is a comment that point that the setter wont be called and that I should use an array instead. I'm looking into this.

The problem is that you are losing the contents of your surrogate List<DictionaryEntry> DictionaryStringInt property during deserialization . The workaround is to change it to an array:

        DictionaryEntry [] DictionaryStringInt
        {
            get
            {
                if (dictionaryStringInt == null)
                    return null;
                List<DictionaryEntry> list = new List<DictionaryEntry>();
                foreach (KeyValuePair<string, int> element in dictionaryStringInt)
                {
                    list.Add(new DictionaryEntry(element.Key, element.Value));
                }
                return list.ToArray();
            }

            set
            {
                if (value == null)
                    return;
                Dictionary<string, int> dictionary = new Dictionary<string, int>();
                foreach (DictionaryEntry entry in value)
                {
                    dictionary.Add(entry.Key, entry.Value);
                }

                dictionaryStringInt = dictionary;
            }
        }

For an explanation of why a List<DictionaryEntry> surrogate property fails during deserialization, see Cannot deserialize XML into a list using XML Deserializer . As explained there:

  1. XmlSerializer calls the getter to get the list. If null, it allocates a list and sets it via the setter. It holds onto the list in some local variable while reading it.

  2. It deserializes each list element, and adds it to the list it is holding.

  3. And that's it. It never calls the containing class's list property setter afterwards. Thus the contents of the list are never populated into your dictionary.

  4. But, since an array cannot be resized once allocated, it must be allocated and set back after its contents are read and deserialized. Thus, an array property can function as a surrogate during deserialization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM