我正在尝试使用XML Schema并将关系转换为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
关键字来隐藏&#34;隐藏&#34;继承的成员,但我听说在序列化这个对象时,XML序列化程序可能无法正确处理这个。
有没有人有任何建议如何正确地将我的架构与C#类关联起来,并且仍然能够序列化我的c#对象以纠正将传递XML Schema Validation的XML对象?
编辑:我尝试使用Xsd2Code和内置的xsd.exe
工具来处理正确的C#类,但它们不会生成我需要的细节。特别是在我上面描述的情况下。
答案 0 :(得分:2)
当您想要做一些更复杂的事情时,.NET XML序列化会变得混乱。
您可以在这些场景中采用的一种方法是使用代理类进行XML序列化和反序列化,而不是直接在应用程序中处理的类型。
在您的情况下,由于您正在对类型进行限制,因此基类可能已经是[de]序列化的适当代理类,因为您可以适应受限类型的XML数据也应该适合基类型。下面的示例采用了这种方法,但如果这对您不起作用,那么您可以定义一个单独的代理类型,该类型仅用于基本的XML [de]序列化和受限类型到相应的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
包含BaseMemberType
,DerivedType
限制BaseType
使用DerivedMemberType
代替会员。请注意在使用XmlIgnore
关键字隐藏基类中的属性的new
的使用,以及为序列化使用单独的虚拟属性,以解决{ {1}} - ed属性不能使用.NET XML序列化代码。
在使用[de]序列化代理时,您应该记住的一个警告是,如果您有一个集合而不是一个对象(new
vs List<MyType>
),则允许{{{ 1}},那么你将需要比单个对象案例更深入的代理。这是因为XML序列化程序将添加到代理属性的getter返回的集合中,而不是直接在代理属性上设置。解决方案是安排您的代理财产与其代理的财产进行责任交换。这可以通过为代理数据和&#34; real&#34;提供私有成员来实现。面向应用程序的数据,但它由代理和非代理属性强制执行,在给定时间只设置一个或另一个,并且在需要时进行它们之间的转换。