实现IXmlSerializable要求Collection属性具有二传手 [英] Implementing IXmlSerializable Requires Collection Property to Have Setter

查看:53
本文介绍了实现IXmlSerializable要求Collection属性具有二传手的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义类型的collection属性,该属性继承自BindingList.当前,即使它没有设置器,也可以通过XmlSerializer对其进行序列化.我现在尝试在此自定义集合类上实现IXmlSerializable,并看到仅当我的集合属性具有Setter时才调用WriteXml()和ReadXml()接口方法.为什么序列化现在会忽略此属性,除非在正确序列化之前没有一个Setter时没有一个.

I have a collection property that is of a custom type which inherits from BindingList. Currently, this property gets serialized via XmlSerializer even though it has no Setter. I now am trying to implement IXmlSerializable on this custom collection class and see that the WriteXml() and ReadXml() interface methods only get called if my collection property has a Setter. Why does serialization ignore this property now unless there is a Setter when before it serialized correctly without one.

要复制:

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

First, have a class called "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):

Next have create the collection Class "MyCollectionType" (Note that IXmlSerializable is purposely missing in the snippet to start off with):

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()中添加一些代码以序列化和反序列化项目":

Lastly, add some code in Main() to Serialize and Deserialize an "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);
            }
        }

因此,如果按原样运行,则应看到它无需设置器即可进行序列化和反序列化.当前,该集合未在上面的代码段中列出"IXmlSerializable",但是方法就在那里.因此,如果现在返回并向MyCollectionType类添加"IXmlSerializable",然后再次运行,您将注意到collection属性未序列化,并且未调用WriteXml()和ReadXml()方法.另请注意,如果添加一个空的Setter,则这些方法将突然被调用.

So, if you run that as-is you should see that it serializes and deserializes without a Setter. Currently, the collection doesn't list "IXmlSerializable" in the snippet above, but the methods are there. So if you now go back and add "IXmlSerializable" to the MyCollectionType class and run again you will notice that the collection property isn't serialized and the WriteXml() and ReadXml() methods don't get called. Also note that if you add an empty Setter those methods will suddenly get called.

推荐答案

这是已记录的行为.在介绍XML序列化中对此进行了解释,尽管不清楚:

This is the documented behavior. It is explained, albeit unclearly, in Introducing XML Serialization:

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

XML serialization does not convert methods, indexers, private fields, or read-only properties (except read-only collections). To serialize all an object's fields and properties, both public and private, use the DataContractSerializer instead of XML serialization.

如您所见,只读属性通常不进行序列化-除了只读集合.但是微软这是什么意思呢?集合毕竟不是财产.

As you can see, get-only properties are in general not serialized -- except for read-only collections. But what does Microsoft mean by this? A collection is not a property after all.

它们的含义如下:

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

(顺便说一句,这意味着,如果您在包含类型的构造函数中将项目添加到集合中,然后对其进行序列化和反序列化,则默认项目将被复制 .有关原因的说明,请参见使用代码默认值对集合属性进行XML反序列化.如果我反序列化您的 Item 类,我会看到这种情况.)

(Incidentally, this means that, if you add items to your collection in the containing type's constructor, then serialize and deserialize it, the default items will get duplicated. For an explanation of why, see XML Deserialization of collection property with code defaults. If I deserialize your Item class I see this behavior.)

这对您的情况如何适用?好了,当您使集合实现 IXmlSerializable 时,序列化程序不再将其解释为集合;而是,序列化器不再将其解释为集合.它将其解释为黑匣子.因此,其关于收款的特殊规则不再适用.现在,引用集合的属性必须是可读写的. XmlSerializer 本身将构造一个实例,对其进行反序列化,然后将其设置为其父级,就像其他任何非集合属性值一样.

How does this apply in your case? Well, when you make your collection implement IXmlSerializable, the serializer no longer interprets it as a collection; it interprets it as a black box. Thus its special rules for collections no longer apply. The property referring to your collection must now be read/write; XmlSerializer will construct an instance itself, deserialize it, and set it into its parent just like any other non-collection property value.

这篇关于实现IXmlSerializable要求Collection属性具有二传手的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆