0

I have this class in C#

public class ExerciseDTO {
    Dictionary<String, String> qa;
    private String materialId, content, topic;

    //constructors

    //properties

    public void makePersistent(String path) {
        Stream outputStream = File.OpenWrite(path + @"\" + this.topic + ".xml");
        XmlSerializer serializer = new XmlSerializer(typeof(ExerciseDTO));
        serializer.Serialize(outputStream, this);
        outputStream.Flush();
        outputStream.Close();
    }
}

Calling the makePersistent method makes the app throw an exeption with message An error occured while reflecting object of type ExerciseDTO. Why can't I serialize instances of this class?

leppie
  • 115,091
  • 17
  • 196
  • 297
Sayo Oladeji
  • 741
  • 4
  • 15
  • 28

3 Answers3

4

Why can't I serialize instances of this class?

Because the XmlSerializer class doesn't support serializing Dictionary<TKey, TValue> properties.

As an alternative you could use the DataContractSerializer which supports dictionaries.

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • The error says it had problems reflecting the object, I think the reflection implementation in the .NET platform should be independent of the XmlSerializer. Are you sure its only the XmlSerializer that can't persist `Dictionary` or all serializers? – Sayo Oladeji Mar 30 '13 at 11:51
  • 1
    No, only the `XmlSerializer` doesn't support Dictionaries. The [`DataContractSerializer`](http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx) works perfectly fine with dictionary types. I have updated my answer to include this information. – Darin Dimitrov Mar 30 '13 at 12:02
  • Thats brilliant then; you mean I can serialize a dictionary with the Binary serializer, right? Who care's about XML anyway? I just need to get my object persisted and retrieved. – Sayo Oladeji Mar 30 '13 at 12:50
0
[Serializable]
public class ExerciseDTO {
...
}
  • You should also have a default (argument free) constructor
  • You should also make your property public, if you want to automatically serialize it
  • serialization of a Dictionary<> is not supported by .net, there are however workrounds, for instance this post.

Edit: as commented below: it should be "serialization of a Dictionary<> is not supported by the XmlSerializer class".

Community
  • 1
  • 1
David
  • 15,894
  • 22
  • 55
  • 66
  • *serialization of a Dictionary<> is not supported by .net* Are you kidding me??? I even found out that it can't serialize references specified as interface types! WTH??? Now I think its accurate to say that .NET is the worst platform I've ever programmed on! I'll never use it for anything asides WindowsPhone again! Java excels by far! – Sayo Oladeji Mar 30 '13 at 11:56
  • 1
    `serialization of a Dictionary<> is not supported by .net` is not a true statement. A more correct statement is `serialization of a Dictionary<> is not supported by the XmlSerializer class`. You could use the `DataContractSerializer` class which supports dictionaries. – Darin Dimitrov Mar 30 '13 at 12:06
  • @DarinDimitrov, we always talk sth in context, I had already offered a link to get this done in .net, so you comment seems to be..., I don't know, I just wish that one can find sth useful from my answer, and I also hope that people can find sth useful from your comments as well. Anyway, I give an upvote for your updated comment. – David Mar 30 '13 at 12:09
0

What Darin said, the Dictionary is not XML serializable. You can create your own XmlSerializableDictionary. There are plenty good examples on the web. Here is one:

http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx

In case the link dies in the future, a copy/paste:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue>
    : Dictionary<TKey, TValue>, IXmlSerializable
{
    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
        bool wasEmpty = reader.IsEmptyElement;

        reader.Read();

        if (wasEmpty)
            return;

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");
            reader.ReadStartElement("key");

            TKey key = (TKey)keySerializer.Deserialize(reader);

            reader.ReadEndElement();
            reader.ReadStartElement("value");

            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();
            this.Add(key, value);
            reader.ReadEndElement();
            reader.MoveToContent();
        }

        reader.ReadEndElement();
    } 

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));

        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();
            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
    }
    #endregion
}
bas
  • 13,550
  • 20
  • 69
  • 146