XmlSerializer的和IEnumerable:序列化可能的W / O参数的构造函数:错误? [英] XmlSerializer and IEnumerable: Serialization possible w/o parameterless constructor: Bug?

查看:125
本文介绍了XmlSerializer的和IEnumerable:序列化可能的W / O参数的构造函数:错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的项目中,我们extensivly使用XmlSerializer的。一次偶然的机会,我发现一个类W / OA参数的构造器。我认为这必须打破序列化进程,但事实并非如此。

通过研究这个问题,我发现,这XmlSerializer的序列化/反序列化的行为时,一个奇怪的的IEnumerable 的:

  • 可枚举的所有元素序列
  • 类是实施的添加(对象)要求的方法
  • 在它忽略了,可能是在这个类中的所有其他属性。
  • 在它调用与这个属性的getter和重用序列化的返回的实例(允许XmlSerializer的工作瓦特/ OA参数的构造函数)。

请看看下面的例子。野趣部分是ODD1,ODD2。需要注意的是good5和good6都是假的,我希望他们是真的。

还有一个原因是对这种行为?

我可以手动执行时的IXmlSerializable XmlSerializer的重用反序列化的属性返回一个实例?

  System.Collections中使用;
使用System.Collections.Generic;
使用System.IO;
使用的System.Xml;
使用System.Xml.Schema;
使用的System.Xml.Serialization;

命名空间测试
{
    公共静态类节目
    {
        公共静态无效的主要()
        {
            HostingClass主机=新HostingClass();

            host.AutomaticSerialization.StringProperty =自动;
            host.SelfImplementedSerialization.StringProperty =自我;

            布尔good1 = host.AutomaticSerialization.FromConstructor ==参数;
            布尔good2 = host.SelfImplementedSerialization.FromConstructor ==参数;
            布尔good3 = host.AutomaticSerialization.StringProperty ==AUTO;
            布尔good4 = host.SelfImplementedSerialization.StringProperty ==自我;

            XmlSerializer的序列化=新的XmlSerializer(typeof运算(HostingClass));

            使用(StringWriter的SW =新的StringWriter())
            {
                serializer.Serialize(SW,主机);

                用(StringReader SR =新StringReader(sw.ToString()))
                {
                    主机=(HostingClass)serializer.Deserialize(SR);
                }
            }

            布尔good5 = host.AutomaticSerialization.FromConstructor == NULL; //为假
            布尔good6 = host.AutomaticSerialization.StringProperty ==AUTO; //为假

            布尔good7 = host.SelfImplementedSerialization.FromConstructor == NULL;
            布尔good8 = host.SelfImplementedSerialization.StringProperty ==自我;

        }
    }

    公共类HostingClass
    {
        私人SelfImplementedSerialization _selfImplementedSerialization;
        公共SelfImplementedSerialization SelfImplementedSerialization
        {
            得到
            {
                返回_selfImplementedSerialization
                       ? (_selfImplementedSerialization =新SelfImplementedSerialization(参数));
            }
            集合{_selfImplementedSerialization =价值; }
        }

        私人AutomaticSerialization _automaticSerialization;
        公共AutomaticSerialization AutomaticSerialization
        {
            得到
            {
                返回_automaticSerialization
                       ? (_automaticSerialization =新AutomaticSerialization(参数)); //反序列化返回的对象用于
            }
            集合{_automaticSerialization =价值; }
        }
    }

    公共类SelfImplementedSerialization:IXmlSerializable的,IEnumerable的< INT>
    {
        公共SelfImplementedSerialization(){}
        公共SelfImplementedSerialization(字符串参数)
        {
            FromConstructor =参数;
        }

        公共字符串StringProperty {获得;组; }
        [XmlIgnore]
        公共字符串FromConstructor {获得;组; }

        公共无效的ReadXml(XmlReader的读者)
        {
            reader.ReadStartElement();
            StringProperty = reader.ReadElementString(StringProperty);
            reader.ReadEndElement();
        }

        公共无效中WriteXML(XmlWriter的作家)
        {
            writer.WriteElementString(StringProperty,StringProperty);
        }

        公众的IEnumerator< INT>的GetEnumerator()
        {
            收益率的回报1;
            收益率回归2;
        }

        IEnumerator的IEnumerable.GetEnumerator(){返回的GetEnumerator(); }
        公众的XmlSchema的getSchema(){返回NULL; }
    }


    公共类AutomaticSerialization:IEnumerable的<诠释>
    {
        // ODD1:序列​​化可能的W / O型的公共参数构造函数
        //公共AutomaticSerialization(){}
        公共AutomaticSerialization(字符串参数)
        {
            FromConstructor =参数;
        }

        // ODD2:元素没有序列号,只有IEnumerable接口是序列化
        [的XmlElement(SP)]
        公共字符串StringProperty {获得;组; }
        [XmlIgnore]
        公共字符串FromConstructor {获得;组; }

        公众的IEnumerator< INT>的GetEnumerator()
        {
            收益率的回报1;
            收益率回归2;
        }

        公共无效添加(对象o)
        {
            XmlSerializer的序列化的时候IEnumerables //要求
        }

        IEnumerator的IEnumerable.GetEnumerator(){返回的GetEnumerator(); }
    }
}
 

解决方案

的原因行为,这是它一贯的工作方式。

XmlSerializer类

  

注意

     

的XmlSerializer 给予特别   治疗以实现类   的IEnumerable 的ICollection 。一类   实现的IEnumerable 绝   实现公共添加方法   带有一个参数。添加   方法的参数必须是相同的   类型从返回的当前   从返回的值属性   的GetEnumerator ,或该类型的一个   基地。一个类实现   的ICollection (如 Col​​lectionBase的)   除了的IEnumerable 必须有一个   公共项目索引属性(索引   在C#),它的整数,它   必须有一个公共Count属性   整数类型。该参数添加   方法必须是相同的类型是   从项目属性返回,或   一个该类型的基地。对于类   实现的ICollection ,值   序列化的检索   索引项属性,而不是通过调用   的GetEnumerator

In our project we extensivly use the XmlSerializer. By chance I found a class w/o a parameterless contructor. I thought this must break the serialization process but it did not.

By investigating this issue I found out, that the XmlSerializer behaves strange when serializing/deserializing an IEnumerable:

  • All elements of the enumerable are serialized
  • The class is required to implement an Add(object) method
  • It ignores all other properties that may be in this class.
  • It calls a getter with this property and reuses the returned instance for serialization (which allows the XmlSerializer to work w/o a parameterless constructor).

Please have a look at the example that follows. Intersting parts are ODD1, ODD2. Note that good5 and good6 are false, when I expected them to be true.

Is there a reason for this behaviour?

Can I make XmlSerializer reuse an instance returned by a property for deserialization when implementing IXmlSerializable by hand?

using System.Collections;
using System.Collections.Generic;   
using System.IO;    
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Test
{
    public static class Program
    {
        public static void Main()
        {
            HostingClass host = new HostingClass();

            host.AutomaticSerialization.StringProperty = "AUTO";
            host.SelfImplementedSerialization.StringProperty = "SELF";

            bool good1 = host.AutomaticSerialization.FromConstructor == "PARAMETER";
            bool good2 = host.SelfImplementedSerialization.FromConstructor == "PARAMETER";
            bool good3 = host.AutomaticSerialization.StringProperty == "AUTO";
            bool good4 = host.SelfImplementedSerialization.StringProperty == "SELF";

            XmlSerializer serializer = new XmlSerializer(typeof(HostingClass));

            using (StringWriter sw = new StringWriter())
            {
                serializer.Serialize(sw, host);

                using (StringReader sr = new StringReader(sw.ToString()))
                {
                    host = (HostingClass)serializer.Deserialize(sr);
                }
            }

            bool good5 = host.AutomaticSerialization.FromConstructor == null; //is false
            bool good6 = host.AutomaticSerialization.StringProperty == "AUTO"; //is false

            bool good7 = host.SelfImplementedSerialization.FromConstructor == null;
            bool good8 = host.SelfImplementedSerialization.StringProperty == "SELF";

        }
    }

    public class HostingClass
    {
        private SelfImplementedSerialization _selfImplementedSerialization;
        public SelfImplementedSerialization SelfImplementedSerialization
        {
            get
            {
                return _selfImplementedSerialization
                       ?? (_selfImplementedSerialization = new SelfImplementedSerialization("PARAMETER"));
            }
            set { _selfImplementedSerialization = value; }
        }

        private AutomaticSerialization _automaticSerialization;
        public AutomaticSerialization AutomaticSerialization
        {
            get
            {
                return _automaticSerialization
                       ?? (_automaticSerialization = new AutomaticSerialization("PARAMETER")); //the returned object is used while deserializing
            }
            set { _automaticSerialization = value; }
        }
    }

    public class SelfImplementedSerialization : IXmlSerializable, IEnumerable<int>
    {
        public SelfImplementedSerialization() { }
        public SelfImplementedSerialization(string parameter)
        {
            FromConstructor = parameter;
        }

        public string StringProperty { get; set; }
        [XmlIgnore]
        public string FromConstructor { get; set; }

        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement();
            StringProperty = reader.ReadElementString("StringProperty");
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString("StringProperty", StringProperty);
        }

        public IEnumerator<int> GetEnumerator()
        {
            yield return 1;
            yield return 2;
        }

        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
        public XmlSchema GetSchema() { return null; }
    }


    public class AutomaticSerialization : IEnumerable<int>
    {
        //ODD1: Serialization possible w/o public parameterless constructor
        //public AutomaticSerialization() {} 
        public AutomaticSerialization(string parameter)
        {
            FromConstructor = parameter;
        }

        //ODD2: Element not serialized, only the IEnumerable Interface is serialized
        [XmlElement("SP")]
        public string StringProperty { get; set; }
        [XmlIgnore]
        public string FromConstructor { get; set; }

        public IEnumerator<int> GetEnumerator()
        {
            yield return 1;
            yield return 2;
        }

        public void Add(object o)
        {
            //requirement of XmlSerializer when serializing IEnumerables
        }

        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    }
}

解决方案

The reason for the behavior is that this is the way it has always worked.

From XmlSerializer class:

Note

The XmlSerializer gives special treatment to classes that implement IEnumerable or ICollection. A class that implements IEnumerable must implement a public Add method that takes a single parameter. The Add method's parameter must be of the same type as is returned from the Current property on the value returned from GetEnumerator, or one of that type's bases. A class that implements ICollection (such as CollectionBase) in addition to IEnumerable must have a public Item indexed property (indexer in C#) that takes an integer, and it must have a public Count property of type integer. The parameter to the Add method must be the same type as is returned from the Item property, or one of that type's bases. For classes that implement ICollection, values to be serialized are retrieved from the indexed Item property, not by calling GetEnumerator.

这篇关于XmlSerializer的和IEnumerable:序列化可能的W / O参数的构造函数:错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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