xsi:type属性搞乱了C#XML反序列化

我使用XSD.exe根据XML模式(.xsd文件)自动生成C#对象。 我正在反序列化OpenCover输出,但其中一个部分类没有正确生成。

这是导致exception的行:

 

这是MethodPoint类的缩短版本:

 [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] public partial class CoverageSessionModulesModuleClassesClassMethodsMethodMethodPoint { private string vcField; private string uspidField; private string ordinalField; private string offsetField; private string slField; private string scField; private string elField; private string ecField; private string becField; private string bevField; private string fileidField; } 

现在我已经浏览了很多.xml文件,但OpenCover输出文件是唯一一个在属性中包含冒号的文件。 MethodPoint对象也是唯一包含属性冒号的对象。 如您所见,该类不包含xsi:type属性,我知道只是添加它将因冒号而无效。 你如何处理xsi前缀?

这是从其中一个OpenCover XML文件生成的原始.xsd

                                                                                                                                                          

简短的回答是您需要手动将[XmlInclude(typeof(SequencePoint))]MethodPoint类:

 [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] [XmlInclude(typeof(SequencePoint))] public partial class CoverageSessionModulesModuleClassesClassMethodsMethodMethodPoint { private string vcField; private string uspidField; private string ordinalField; private string offsetField; private string slField; private string scField; private string elField; private string ecField; private string becField; private string bevField; private string fileidField; } 

如果尚未从MethodPointinheritance,还需要使SequencePointinheritance。

您需要这样做,因为当您使用xsd.exe从XML示例生成XSD ,然后依次生成c#类时,当属性xsi:type="SomePolymoirphicSubType"时,它显然不会自动向基类型添加多态子类型属性xsi:type="SomePolymoirphicSubType"出现在XML中,即使看起来应该如此。

解释如下。 xsi:type属性是{http://www.w3.org/2001/XMLSchema-instance}type缩写,是一个w3c标准属性 ,允许元素显式断言其类型,例如,当它是多态的子类型时预期的元素类型。 XmlSerializer 支持此属性 ,并将使用它来确定要对此类多态类型进行反序列化的实际对象类型。 但是,需要使用XmlIncludeAttribute 提前通知所有可能的类型。 因此,如果我创建以下类型层次结构:

 [XmlInclude(typeof(SequencePoint))] public class MethodPoint { } public class SequencePoint : MethodPoint { } 

并按如下顺序排列:

 var test = new SequencePoint(); var serializer = new XmlSerializer(typeof(MethodPoint)); var sb = new StringBuilder(); using (var stream = new StringWriter(sb)) serializer.Serialize(stream, test); Console.WriteLine(sb); 

我得到以下XML:

  

然后,如果我使用var serializer = new XmlSerializer(typeof(MethodPoint))对其进行反var serializer = new XmlSerializer(typeof(MethodPoint)) ,我会返回一个SequencePoint ,而不是它的基类。 如果我使用xsd.exe为这些类生成模式,我得到:

           

注意xs:extension ? 这就是XSD如何表示多态子类型。 然后,如果我向后运行xsd.exe以重新生成我的类,我得到:

 [System.Xml.Serialization.XmlIncludeAttribute(typeof(SequencePoint))] [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)] public partial class MethodPoint { } ///  [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)] public partial class SequencePoint : MethodPoint { } 

如您所见, XmlIncludeAttribute存在,结果类等同于原始类。 到目前为止,一切都很完美。

但是,似乎在从示例XML文件中推断出XSD时,xsd.exe没有获取xsi:type属性的存在。 例如,如果我从上面的普通XML创建XSD,结果是:

        

多态子类型完全缺失。 从此XSD生成的类将无法反序列化该XML。

因此,使用xsd.exe从XML样本生成c#类似乎不如从正确的XSD生成它们那样可靠。 具体而言,如果XML文件中出现xsi:type ,则需要手动修复生成的类或生成的XSD以实现所需的层次结构。 这可能是工具中的限制或错误。

(限制/错误也会出现在粘贴XML中作为在内部使用xsd.exe 。)