反序列化到子类问题
Deserializing to a subclass problems
我一直在尝试将一些 XML 反序列化为 class,它是另一个 class 的子 class。当我尝试反序列化到基础 class 时,它起作用了。但是,当 class 反序列化为任何子 class 时,它将失败。
我想知道为什么会这样。这是 OOP 设计违规还是我只是错过了一些东西。谢谢
代码如下:
基地 Class : 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;
}
}
}
}
子class #1 : Rectangle.cs
namespace Shape
{
public class Rectangle : Shape
{
}
}
子class #2 : Square.cs
namespace Shape
{
public class Square : Shape
{
}
}
Class 试图将 XML 反序列化为矩形 (Subclass #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 只能有一个根节点,但您有一个 Shape[] 数组作为根节点。所以我添加到您的 xml NewDataSet。 类 中的对象名称与 xml 中的标签不匹配。所以我将 Xml 元素添加到 类。我还将 XmlAttribute 更改为 XmlElement。 Xml属性在 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;
}
}
}
}
设法找到解决方案。解决方法是将 [XmlRoot("Shape")] 添加到子 classes 中以解决问题。
示例:
[XmlRoot("Shape")]
public class Rectangle : Shape
{ .. }
'Square' class
也一样
我一直在尝试将一些 XML 反序列化为 class,它是另一个 class 的子 class。当我尝试反序列化到基础 class 时,它起作用了。但是,当 class 反序列化为任何子 class 时,它将失败。
我想知道为什么会这样。这是 OOP 设计违规还是我只是错过了一些东西。谢谢
代码如下:
基地 Class : 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;
}
}
}
}
子class #1 : Rectangle.cs
namespace Shape
{
public class Rectangle : Shape
{
}
}
子class #2 : Square.cs
namespace Shape
{
public class Square : Shape
{
}
}
Class 试图将 XML 反序列化为矩形 (Subclass #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 只能有一个根节点,但您有一个 Shape[] 数组作为根节点。所以我添加到您的 xml NewDataSet。 类 中的对象名称与 xml 中的标签不匹配。所以我将 Xml 元素添加到 类。我还将 XmlAttribute 更改为 XmlElement。 Xml属性在 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;
}
}
}
}
设法找到解决方案。解决方法是将 [XmlRoot("Shape")] 添加到子 classes 中以解决问题。
示例:
[XmlRoot("Shape")]
public class Rectangle : Shape
{ .. }
'Square' class
也一样