我正在尝试教我自己如何使用基于属性的序列化程序对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
}
}
答案 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
没有)。