【问题标题】:Implementing IXmlSerializable Requires Collection Property to Have Setter实现 IXmlSerializable 需要 Collection 属性具有 Setter
【发布时间】:2013-03-27 15:09:25
【问题描述】:

我有一个继承自 BindingList 的自定义类型的集合属性。目前,该属性通过 XmlSerializer 进行序列化,即使它没有 Setter。我现在正在尝试在此自定义集合类上实现 IXmlSerializable,并看到 WriteXml() 和 ReadXml() 接口方法只有在我的集合属性具有 Setter 时才会被调用。为什么序列化现在会忽略这个属性,除非有一个 Setter,而在没有 Setter 的情况下正确序列化。

复制:

首先,有一个名为“Item”的类:

public class Item
{
    public Item() {}

    // Generates some random data for the collection
    private MyCollectionType GenerateContent()
    {
        Random ranGen = new Random();
        MyCollectionType collection = new MyCollectionType();

        for (int i = 0; i < 5; i ++)
        {
            collection.Add("Item" + ranGen.Next(0,101));
        }

        return collection;
    }

    public MyCollectionType Items
    {
        get
        {
            if (m_Items == null)
            {
                m_Items = GenerateContent();
            }
            return m_Items;
        }
    }
    private MyCollectionType m_Items = null;
}

接下来创建集合类“MyCollectionType”(请注意,在 sn-p 开始时故意缺少 IXmlSerializable):

public class MyCollectionType : BindingList<string>
{
    public MyCollectionType()
    {
        this.ListChanged += MyCollectionType_ListChanged;
    }

    void MyCollectionType_ListChanged(object sender, ListChangedEventArgs e){ }

    public MyCollectionType(ICollection<string> p)
    {
        this.ListChanged  += MyCollectionType_ListChanged;
    }

    #region Implementation of IXmlSerializable

    public void WriteXml(XmlWriter writer)
    {
        throw new NotImplementedException();
    }

    public void ReadXml(XmlReader reader)
    {
        throw new NotImplementedException();
    }

    public XmlSchema GetSchema() { return null; }

    #endregion
}

最后,在 Main() 中添加一些代码来序列化和反序列化“项目”:

        Item myItem = new Item();
        Item newItem = null;

        // Define an XmlSerializer
        XmlSerializer ser = new XmlSerializer(typeof(Item));

        // Serialize the Object
        using (TextWriter writer = File.CreateText(@"c:\temporary\exportedfromtest.xml"))
        {
            ser.Serialize(writer,myItem);
        }

        // Deserialize it
        using (Stream reader = new FileStream(@"c:\temporary\exportedfromtest.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            using (XmlDictionaryReader xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(reader, XmlDictionaryReaderQuotas.Max))
            {
                newItem = (Item)ser.Deserialize(xmlDictionaryReader);
            }
        }

因此,如果您按原样运行,您应该会看到它在没有 Setter 的情况下进行序列化和反序列化。目前,该集合没有在上面的 sn-p 中列出“IXmlSerializable”,但方法在那里。因此,如果您现在返回并将“IXmlSerializable”添加到 MyCollectionType 类并再次运行,您会注意到集合属性未序列化,并且未调用 WriteXml() 和 ReadXml() 方法。另请注意,如果您添加一个空的 Setter,这些方法将突然被调用。

【问题讨论】:

  • 这和WCF有什么关系?请负责任地标记:)
  • 请贴出代码。

标签: c# xmlserializer ixmlserializable


【解决方案1】:

这是记录在案的行为。 Introducing XML Serialization:

XML 序列化不会转换方法、索引器、私有字段或只读属性(只读集合除外)。要序列化对象的所有字段和属性,包括公共的和私有的,请使用 DataContractSerializer 而不是 XML 序列化。

如您所见,get-only 属性通常不会序列化——除了只读集合。但微软的意思是什么?集合毕竟不是财产。

它们的意思如下:

XML 序列化不会转换仅获取属性或只读字段(具有预初始化集合的仅获取集合值属性除外)

(顺便说一句,这意味着,如果您在包含类型的构造函数中将项目添加到集合中,然后对其进行序列化和反序列化,则默认项目将得到重复。有关原因的说明,请参阅XML Deserialization of collection property with code defaults。如果我反序列化您的 Item 类,我会看到这种行为。)

这如何适用于您的情况?好吧,当你让你的集合实现IXmlSerializable 时,序列化程序不再将它解释为一个集合;它将其解释为一个黑匣子。因此,它对收藏的特殊规则不再适用。引用您的集合的属性现在必须是读/写的; XmlSerializer 将自己构造一个实例,对其进行反序列化,并将其设置为其父级,就像任何其他非集合属性值一样。

【讨论】:

    猜你喜欢
    • 2012-10-26
    • 1970-01-01
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多