XML serialization question

I am trying to teach: how to serialize / deserialize to / from XML using an attribute based serializer. I have put below code together for testing, but it seems that I may have missed a point or two. Can anyone help me and tell me what to do to make this all work? The code below should compile and run just fine, but will throw an exception - something is probably wrong with my attributes.

What did I miss?

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;

namespace XMLSerialisation_test
{
    class Program
    {
        static void Main(string[] args)
        {
            World my_world = new World(new Point(20, 30));

            for (int i = 0; i < 10; i++)
            {
                string property = String.Format("Property no.{0}", i);
                my_world.PushWorldObject(new MyObject(new Point(i, i), property));
            }

            DataContractSerializer world_serializer = new DataContractSerializer(typeof(World));

            try
            {
                using (Stream s = File.Create("output.xml"))
                    world_serializer.WriteObject(s, my_world);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception occured : {0}", e.Message);
            }

        }
    }
}

      

WorldObject.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace XMLSerialisation_test
{
    [DataContract]
    public struct Point // couldn't find the pre-defined Point for some reason
    {
        public Point(double x, double y)
        { X = x; Y = y; }
        [DataMember]
        public double X;
        [DataMember]
        public double Y;
    }

    [DataContract]
    public abstract class WorldObject
    {
        public WorldObject() : this(0.0, 0.0)
        {}

        public WorldObject(Point loc)
        { m_location = loc; }

        public WorldObject(double x, double y)
        { 
            m_location.X = x;
            m_location.Y = y;
        }

        [DataMember]
        public Point Location
        {
            get { return m_location; }
            set { m_location = value; }
        }

        protected Point m_location;
    }

    [DataContract]
    public class MyObject : WorldObject
    {
        public MyObject(string prop)
            : base(0.0, 0.0)
        { m_property = prop; }

        public MyObject(Point p, string prop)
            : base(p)
        { m_property = prop; }

        [DataMember]
        public string Property
        {
            get{ return m_property; }
            set{ m_property = value; }
        }

        private string m_property;
    }
}

      

World.cs

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

namespace XMLSerialisation_test
{
    [DataContract]
    class World
    {
        public World() : this(new Point(10, 10))
        { }

        public World(Point size)
        { m_world_size = size; }

        public bool PushWorldObject(WorldObject o)
        {
            try
            {
                WorldObjects.Add(o);
                return true;
            }
            catch(Exception e)
            {
                Console.WriteLine("Exception occured : {0}", e.Message);
                return false; }
        }


        #region Accessors
        [DataMember]
        public List<WorldObject> WorldObjects
        {
            get { return m_world_objects; }
            set { m_world_objects = value; }
        }
        [DataMember]
        public Point WorldSize
        {
            get { return m_world_size; }
            private set { m_world_size = value; }
        }
        #endregion

        #region Fields
        private List<WorldObject> m_world_objects = new List<WorldObject>();
        private Point m_world_size;
        #endregion
    }
}

      

+2


source to share


3 answers


Try the following:

DataContractSerializer world_serializer = new DataContractSerializer(typeof(World), new List<Type> { typeof(MyObject) });

      

The problem is that PushWorldObject accepts a type WorldObject

, but you are actually passing a type MyObject

. The serializer knows nothing about this type, so it throws an exception. WorldObject is used in the World class, so this type is known by default. However, MyObject is not used internally by World - so you need to manually declare it as "Known".



Alternatively, you can add the KnownType attribute, for example:

[DataContract, KnownType(typeof(MyObject))]
class World
{

      

+2


source


The biggest problem I see is the abstract WorldObject. You will need to use the KnownType attribute (either via config or method name - check MSDN for Known Datatypes ) this is about known subtypes that it might collide with (eg MyObject).



0


source


Just to clarify, if you are serializing to xml in order to have the xml in a known format , then this DataContractSerializer

is a bad choice; you are better off using XmlSerializer

which has more control over the xml layout. You should use the [XmlElement]

/ [XmlAttribute]

/ [XmlType]

/ attributes [XmlRoot]

instead of [DataMember]

etc.

If you just want to use xml because it is text and stores an object, then DataContractSerializer

great; and has other advantages, for example - not requiring a public parameterless constructor (which XmlSerializer

does) and working with private members (which XmlSerializer

does not).

0


source







All Articles