XML序列化问题

时间:2009-10-23 19:50:34

标签: c#

我正在尝试教我自己如何使用基于属性的序列化程序对XML进行序列化/反序列化。我已将下面的代码放在一起用于测试目的,但似乎我可能错过了一两点。任何人都可以帮助我并告诉我怎么做让整个该死的东西正常工作?下面的代码应该编译并运行得很好,但会引发异常 - 我的属性可能有问题。

我错过了什么?

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

3 个答案:

答案 0 :(得分:2)

试试这个:

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

问题是PushWorldObject采用类型WorldObject,但实际上是传递类型MyObject。序列化程序对此类型一无所知,因此抛出异常。 WorldObject在World类中使用,因此默认情况下已知此类型。但是,MyObject并未在World中使用 - 因此您必须手动将其声明为已知。

作为替代方案,您可以像这样添加KnownType属性:

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

答案 1 :(得分:0)

我看到的最大问题是抽象的WorldObject。您需要在那里使用KnownType属性(或通过配置或方法名称 - 检查MSDN“Data Contract Known Types”)来告诉它可能遇到的已知子类型(例如,MyObject)。

答案 2 :(得分:0)

只是为了澄清:如果您为了使xml采用已知格式而序列化为xml ,那么DataContractSerializer是一个糟糕的选择;你最好使用XmlSerializer,它可以更好地控制xml布局。您可以使用[XmlElement] / [XmlAttribute] / [XmlType] / [XmlRoot]属性代替[DataMember]等。

如果您只是想使用xml,因为它是文本并存储对象,那么DataContractSerializer就可以了;并且还有其他优点,例如 - 不要求公共无参数构造函数(XmlSerializer执行),以及使用私有成员(XmlSerializer没有)。