DataContract序列化包含对象的List<>

4
在开发一个测试用例以理解序列化时,我遇到了一个看起来很简单但却无法解决的问题。我想要将多个对象添加到列表<>中,然后对该列表进行序列化(在这种情况下,我使用DataContractJsonSerializer)。创建对象(node1和node2)后,我想将它们添加到List<>(cn)中并进行序列化。但是,在添加node1和node2时,我会收到一个无效参数错误(“无法将'JSON_test.Aspirate'转换为'JSON_test.CompositeNode'”)。我认为这是让数组知道基本类型的问题,但我不知道如何做到这一点,或者是否实际上是这个问题(对所有这些还非常陌生)。谢谢。
namespace JSON_test
{
    class Program
    {
        static void Main(string[] args)
        {
            Aspirate node1 = new Aspirate(25,40);
            Dispense node2 = new Dispense(32,50);
            ObjectToSerialize cn = new ObjectToSerialize();
            cn.CompositeNode.Add (node1);
            cn.CompositeNode.Add (node2);

            MemoryStream stream1 = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ObjectToSerialize));
            ser.WriteObject(stream1, cn.CompositeNode);
            stream1.Position = 0;
            StreamReader sr = new StreamReader(stream1);
            Console.WriteLine(sr.ReadToEnd());
            Console.ReadLine();
        }
    }

    [DataContract]
    public class ObjectToSerialize
    {
        private List<CompositeNode> compNode;
        [DataMember]
        public List<CompositeNode> CompositeNode
        {
            get {return this.CompositeNode;}
            set { this.compNode = value; }
        }

        public ObjectToSerialize()
        { 
        }
    }

    [DataContract]
    public class CompositeNode
    {

    }

    [DataContract]
    public class Aspirate
    {
        [DataMember]
        public string NodeName = "Aspirate";
        [DataMember]
        public double ZTravelHt;
        [DataMember]
        public double IndexHt;

        public Aspirate(double ZTravelHt, double IndexHt)
        {
            this.ZTravelHt = ZTravelHt;
            this.IndexHt = IndexHt;
        }
    }

    [DataContract]
    public class Dispense 
    {
        [DataMember]
        public string NodeName = "Dispense";
        [DataMember]
        public double ZTravelHt;
        [DataMember]
        public double IndexHt;

        public Dispense(double ZTravelHt, double IndexHt)
        {
            this.ZTravelHt = ZTravelHt;
            this.IndexHt = IndexHt;            
        }
    }
}

更新

namespace JSON_test
{
    class Program
    {
        static void Main(string[] args)
        {
            Aspirate node1 = new Aspirate(25,40);
            Dispense node2 = new Dispense(32,50);
            ObjectToSerialize cn = new ObjectToSerialize();
            cn.CompositeNode.Add (node1);
            cn.CompositeNode.Add (node2);

            MemoryStream stream1 = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ObjectToSerialize),
                new Type[] {typeof (Aspirate), typeof (Dispense)});
            ser.WriteObject(stream1, cn.CompositeNode);
            stream1.Position = 0;
            StreamReader sr = new StreamReader(stream1);
            Console.WriteLine(sr.ReadToEnd());
            Console.ReadLine();
        }
    }

    [DataContract]
    [KnownType(typeof(Aspirate))]
    [KnownType(typeof(Dispense))]
    public class ObjectToSerialize
    {
        private List<CompositeNode> compNode = new List<CompositeNode>();

        [DataMember]
        public List<CompositeNode> CompositeNode 
        {
            get {return this.compNode;}
            set { this.compNode = value; }
        }

        public ObjectToSerialize()
        { 

        }
    }

    [DataContract]
    [KnownType(typeof(Aspirate))]
    [KnownType(typeof(Dispense))]
    public class CompositeNode
    {

    }

    [DataContract]
    public class Aspirate : CompositeNode
    {
        [DataMember]
        public string NodeName = "Aspirate";
        [DataMember]
        public double ZTravelHt;
        [DataMember]
        public double IndexHt;

        public Aspirate(double ZTravelHt, double IndexHt)
        {
            this.ZTravelHt = ZTravelHt;
            this.IndexHt = IndexHt;
        }
    }

    [DataContract]
    public class Dispense : CompositeNode
    {
        [DataMember]
        public string NodeName = "Dispense";
        [DataMember]
        public double ZTravelHt;
        [DataMember]
        public double IndexHt;

        public Dispense(double ZTravelHt, double IndexHt)
        {
            this.ZTravelHt = ZTravelHt;
            this.IndexHt = IndexHt;            
        }
    }
}
1个回答

7
您可以在ObjectToSerialize中添加一个KnownTypeAttribute,以便让序列化程序知道应该期望哪些类型:
[DataContract]
[KnownType(typeof(Aspirate))]
[KnownType(typeof(Dispense))]
public class ObjectToSerialize
{
     ....
}

我知道 AspirateDispense 类是从 CompositeNode 派生的?但这在代码示例中并不清楚。
顺便说一下,你的代码有错误。
get {return this.CompositeNode;}    

should be:

get {return this.compNode;}    

更新:回答您在评论中的问题:您必须在ObjectToSerialize的构造函数中初始化集合:

public ObjectToSerialize()
{
    this.compNode = new List<CompositeNode>();
}

Update 2:错误的行是:
ser.WriteObject(stream1, cn.CompositeNode);

这应该是:

ser.WriteObject(stream1, cn);

顺便说一下,你可以直接写成这样:
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ObjectToSerialize)); 

您已经通过使用属性定义了已知类型。将已知类型添加到构造函数中是多余的。

谢谢。这让我朝着正确的方向前进了一步。我添加了KnownTypes,纠正了错误,并在Aspirate和Dispense类中添加了“:CompositeNode”。现在它可以编译,但是当节点添加到列表中时会出现NullReferenceException。这告诉我在CompositeNode类中需要一些东西,但我的经验不足。有什么建议吗? - user269689
你需要在classObjectToSerialize中初始化compNode。 - Richard Schneider
再次感谢您的帮助。我将“private List<CompositeNode> compNode”更改为“private List<CompositeNode> compNode = new List<CompositeNode>();”。现在该列表已填充了两个节点,但我遇到了SerializationException - “ArrayOfCompositeNode:http://schemas.datacontract.org/2004/07/JSON_test'未被预期”的问题。 - user269689
@user269689 - 嗯,那不应该发生。你能给我们展示一下你代码的当前版本吗? - Elian Ebbing
这个评论框里的字符太多了。不确定如何发布新版本。 - user269689
@Elan Ebbing - 谢谢。你的第二次更新解决了问题。再次感谢。 - user269689

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接