【问题标题】:XML object binding of types derived by restriction通过限制派生的类型的 XML 对象绑定
【发布时间】:2015-01-21 16:52:36
【问题描述】:

我正在尝试采用 XML 模式并将关系转换为 C# 类。我遇到的情况如下:

我在架构中有一个复杂类型,它有 4 个元素,都是某种类型:

<xs:complexType name="ReportingBaseType" abstract="true">
    <xs:sequence>
        <xs:element name="Category" type="ent:ReportingCategoryConceptType" minOccurs="0" maxOccurs="0"/>
        <xs:element name="Frequency" type="ent:ReportingFrequencyType"/>
        <xs:element name="AdjustmentFrequency" type="ent:ReportingAdjustmentFrequencyType"/>
        <xs:element name="FirstReportDueDate" type="ent:CXMLDateType" minOccurs="0" maxOccurs="0"/>
    </xs:sequence>
</xs:complexType>

接下来,我有多种复杂类型可以限制或扩展这种类型:

<xs:complexType name="ReportingClassA">
   <xs:restriction base="ReportingBaseType">
    <xs:sequence>
        <xs:element name="Category" type="ent:ReportingClassAType" minOccurs="0" maxOccurs="0"/>
        <xs:element name="Frequency" type="ent:FequencyForThisClassType"/>
    </xs:sequence>
   </restriction>
</xs:complexType>

<xs:complexType name="ReportingClassB">
   <xs:restriction base="ReportingBaseType">
    <xs:sequence>
        <xs:element name="Category" type="ent:NewTypeForThisClass" minOccurs="0" maxOccurs="0"/>
        <xs:element name="Frequency" type="ent:AnotherNewType"/>
        <xs:element name="AdjustmentFrequency" type="ent:ThisIsADifferntTypeThenParent"/>
        <xs:element name="FirstReportDueDate" type="ent:AndAnotherNewType" minOccurs="0" maxOccurs="
    </xs:sequence>
  </restriction>
</xs:complexType>

我如何(在 C# 中)从父类 (ReportingBaseType) 派生但具有不同类型的属性,就像它们在 Schema 中定义的一样?

我曾想过在派生类上定义我的属性以“隐藏”继承的成员时使用new 关键字,但我听说在序列化此对象时,XML 序列化程序可能无法正确处理。

是否有人对如何正确地将我的架构与 C# 类相关联并且仍然能够将我的 C# 对象序列化以更正将通过 XML 架构验证的 XML 对象有任何建议?

编辑:我尝试使用 Xsd2Code 和内置的 xsd.exe 工具来处理正确的 C# 类,但它们不会生成我需要的详细信息。尤其是在我上面描述的情况下。

【问题讨论】:

    标签: c# .net xml serialization xml-serialization


    【解决方案1】:

    当您想做一些更复杂的事情时,.NET XML 序列化可能会变得混乱。

    您可以在这些场景中采用的一种方法是使用代理类进行 XML 序列化和反序列化,而不是直接在应用程序中处理的类型。

    在您的情况下,由于您正在限制类型,因此基类可能已经是 [反] 序列化的适当代理类,因为您可以适合受限类型的 XML 数据也应该适合基类型。下面的示例采用这种方法,但如果这对您不起作用,那么您可以定义一个单独的代理类型,该类型仅用于将基本类型和受限类型的 XML [反]序列化到其相应的 C# 类。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    
    namespace XmlTest
    {
        public class BaseMemberType
        {
            public string SomeValue
            {
                get;
                set;
            }
        }
    
        public abstract class BaseType
        {
            [XmlElement("Member", Type=typeof(BaseMemberType))]
            [EditorBrowsable(EditorBrowsableState.Never)]
            public virtual BaseMemberType _MemberSerializer
            {
                get
                {
                    return Member;
                }
                set
                {
                    this.Member = (BaseMemberType)value;
                }
            }
    
            [XmlIgnore()]
            public BaseMemberType Member
            {
                get;
                set;
            }
        }
    
        public class DerivedMemberType
        {
            public int SomeValue
            {
                get;
                set;
            }
        }
    
        public class DerivedType : BaseType
        {
            [XmlIgnore()]
            [EditorBrowsable(EditorBrowsableState.Never)]
            public override BaseMemberType _MemberSerializer
            {
                get
                {
                    return new BaseMemberType()
                    {
                        SomeValue = this.Member.SomeValue.ToString()
                    };
                }
                set
                {
                    this.Member = new DerivedMemberType()
                    {
                        SomeValue = int.Parse(value.SomeValue)
                    };
                }
            }
    
            [XmlIgnore()]
            public new DerivedMemberType Member
            {
                get;
                set;
            }
        }
    
        public class AnotherDerivedType : BaseType
        {
        }
    
        public class RootElement
        {
            public DerivedType First
            {
                get;
                set;
            }
    
            public AnotherDerivedType Second
            {
                get;
                set;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var serializer = new System.Xml.Serialization.XmlSerializer(typeof(RootElement));
                RootElement rootElement = null;
                string xml = @"
    <RootElement>
    <First>
    <Member><SomeValue>1234</SomeValue></Member>
    </First>
    <Second>
    <Member><SomeValue>Some string</SomeValue></Member>
    </Second>
    </RootElement>
    ";
                using(var reader = new System.IO.StringReader(xml))
                {
                    rootElement = (RootElement)serializer.Deserialize(reader);
                }
    
                Console.WriteLine("First.Member.SomeValue: {0}", rootElement.First.Member.SomeValue);
                Console.WriteLine("Second.Member.SomeValue: {0}", rootElement.Second.Member.SomeValue);
    
                using (var writer = new System.IO.StringWriter())
                {
                    serializer.Serialize(writer, rootElement);
                    string serialized = writer.ToString();
                    Console.WriteLine("Deserialized: ");
                    Console.WriteLine(serialized);
                }
            }
        }
    }
    

    您会看到BaseMemberType 表示受DerivedMemberType 限制的基本类型,因此字符串成员被限制为int。 BaseType 包含 BaseMemberTypeDerivedType 限制 BaseType 使用 DerivedMemberType 代替成员。注意使用new 关键字在隐藏基类中的属性上使用XmlIgnore,并使用单独的虚拟属性进行序列化,以解决new-ed属性不适用于 .NET XML 序列化代码。

    在使用代理进行 [反] 序列化时应牢记的一个警告是,如果您有一个集合而不是单个对象(List&lt;MyType&gt;MyType),允许 maxOccurs &gt; 1,那么您将需要比在单个对象情况下更深入的代理。这是因为 XML 序列化器将添加到代理属性的 getter 返回的集合中,而不是直接在代理属性上设置。一个解决方案是安排您的代理财产与其代理的财产进行责任交换。这可以通过为代理数据和“真实”面向应用程序的数据设置私有成员来完成,但它由代理和非代理属性强制执行,在给定时间仅设置一个或另一个,并且它们之间的转换会在需要时发生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-05
      相关资源
      最近更新 更多