【问题标题】:Deserializing to a subclass problems反序列化到子类问题
【发布时间】:2015-05-23 06:53:35
【问题描述】:

我一直在尝试将一些 XML 反序列化为一个类,该类是另一个类的子类。当我尝试反序列化为基类时,它可以工作。但是,当该类被反序列化为任何子类时,它将失败。

我想知道为什么会这样。这是违反 OOP 设计还是我只是错过了一些东西。谢谢

下面是代码:

基类:Shape.cs

namespace Shape
{
    using System.Xml.Serialization;


    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    [System.Xml.Serialization.XmlRootAttribute(IsNullable = false)]
    [KnownType(typeof(Rectangle))]
    [KnownType(typeof(Square))]

    public partial class Shape
    {

        private string widthField;

        private string heightField;

        private string colorField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Width
        {
            get
            {
                return this.widthField;
            }
            set
            {
                this.widthField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Height
        {
            get
            {
                return this.heightField;
            }
            set
            {
                this.heightField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Color
        {
            get
            {
                return this.colorField;
            }
            set
            {
                this.colorField = value;
            }
        }
    }

    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
    public partial class NewDataSet
    {

        private Shape[] itemsField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("Shape")]
        public Shape[] Items
        {
            get
            {
                return this.itemsField;
            }
            set
            {
                this.itemsField = value;
            }
        }
    }
}

子类 #1:Rectangle.cs

namespace Shape
{
    public class Rectangle : Shape
    {
    }
}

子类 #2:Square.cs

namespace Shape
{
    public class Square : Shape
    {
    }
}

试图将 XML 反序列化为 Rectangle 的类(子类 #1)

    string xmlSample = "<?xml version=\"1.0\" ?><Shape xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><Width>2</Width><Height>5</Height><Color>Red</Color></Shape>";
    //Shape.Shape shape = Utilities.ByteArrayToObject<Shape.Shape>(Utilities.XmlStringToBytes(xmlSample)); <-- Works OK
    Shape.Rectangle rect = Utilities.ByteArrayToObject<Shape.Rectangle>(Utilities.XmlStringToBytes(xmlSample));  //<-- Will fail

形状的 XSD 架构:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Shape">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Width" type="xs:string" minOccurs="0" />
        <xs:element name="Height" type="xs:string" minOccurs="0" />
        <xs:element name="Color" type="xs:string" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="Shape" />
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

【问题讨论】:

    标签: c# xml xsd deserialization xmlserializer


    【解决方案1】:

    见下面的代码。我发现了很多问题。 XML 只能有一个根节点,但您有一个 Shape[] 数组作为根。所以我添加到你的 xml NewDataSet。类中对象的名称与 xml 中的标签不匹配。所以我将 XmlElement 添加到类中。我还将 XmlAttribute 更改为 XmlElement。 XmlAttribute 在 XML 中具有等号。您在尖括号之间的 Xml 中有 TEXT。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    using System.IO;
    using System.Data;
    
    
    namespace Shape
    {
        class Program
        {
            static void Main(string[] args)
            {
                string xmlSample = "<?xml version=\"1.0\"?><NewDataSet xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><Shape xsi:type=\"Rectangle\"><Width>2</Width><Height>5</Height><Color>Red</Color></Shape></NewDataSet>";
                StringReader reader = new StringReader(xmlSample);
    
                XmlSerializer xs = new XmlSerializer(typeof(NewDataSet));
                NewDataSet ds = (NewDataSet)xs.Deserialize(reader);
    
            }
    
        }
        /// <remarks/>
        [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
        [System.SerializableAttribute()]
        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
        [XmlInclude(typeof(Rectangle))]
        [XmlInclude(typeof(Square))]
        [XmlRoot("Shape")]
        public partial class Shape
        {
            private string widthField;
            private string heightField;
            private string colorField;
    
            /// <remarks/>
            [XmlElement("Width")]
            public string Width
            {
                get
                {
                    return this.widthField;
                }
                set
                {
                    this.widthField = value;
                }
            }
    
            /// <remarks/>
            [XmlElement("Height")]
            public string Height
            {
                get
                {
                    return this.heightField;
                }
                set
                {
                    this.heightField = value;
                }
            }
    
            /// <remarks/>
            [XmlElement("Color")]
            public string Color
            {
                get
                {
                    return this.colorField;
                }
                set
                {
                    this.colorField = value;
                }
            }
        }
        [XmlRoot("Rectangle")]
        public class Rectangle : Shape
        {
        }
        [XmlRoot("Square")]
        public class Square : Shape
        {
        }
    
        /// <remarks/>
        [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
        [System.SerializableAttribute()]
        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
        //[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
        [XmlRoot("NewDataSet")]
        public partial class NewDataSet
        {
    
            private Shape[] itemsField;
    
            /// <remarks/>
            [XmlElement("Shape")]
            public Shape[] Items
            {
                get
                {
                    return this.itemsField;
                }
                set
                {
                    this.itemsField = value;
                }
            }
        }
    
    
    }
    ​
    

    【讨论】:

    • 嗨@jdweng ,似乎能够使用上述代码反序列化为“Shape”类。但我试图反序列化成一个“方形”类,它也失败了。隐式转换为 Square 类:Shape.Square square = (Shape.Square)ds.Items[0];。抛出的错误是'无法将'Shape.Shape'类型的对象转换为'Shape.Square''有什么想法吗?谢谢!
    【解决方案2】:

    转换为基类型在 C# 中被认为是安全的隐式类型转换。但反之则不然。

    【讨论】:

      【解决方案3】:

      设法找到解决方案。解决方法是向子类添加 [XmlRoot("Shape")] 来解决问题。

      例子:

      [XmlRoot("Shape")]
      public class Rectangle : Shape
      { .. }
      

      'Square' 类也一样

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-05
        相关资源
        最近更新 更多