实现IXmlSerializable需要Collection属性具有Setter

时间:2013-03-27 15:09:26

标签: c# xmlserializer ixmlserializable

我有一个自定义类型的集合属性,它继承自BindingList。目前,即使没有Setter,此属性也会通过XmlSerializer进行序列化。我现在正在尝试在此自定义集合类上实现IXmlSerializable,并且看到只有在我的集合属性具有Setter时才调用WriteXml()和ReadXml()接口方法。为什么序列化现在忽略此属性,除非在没有一个序列化之前有一个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”(请注意,在片段中故意缺少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”:

        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的情况下序列化和反序列化。目前,该集合未在上面的代码段中列出“IXmlSerializable”,但方法是存在的。因此,如果现在返回并将“IXmlSerializable”添加到MyCollectionType类并再次运行,您将注意到collection属性未被序列化,并且不会调用WriteXml()和ReadXml()方法。另请注意,如果添加空Setter,则会突然调用这些方法。

1 个答案:

答案 0 :(得分:3)

这是记录在案的行为。虽然不清楚,但在Introducing XML Serialization

中对此进行了解释
  

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

正如您所看到的,只有get-only属性通常不会被序列化 - 除了只读集合。但微软对此意味着什么呢?毕竟,集合不是属性。

他们的意思如下:

XML序列化不会转换仅限get属性或只读字段(除了使用预初始化集合的只获取集合值的属性)

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

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