C#中XML Schema的代码生成有哪些限制?

我已经看到了几个关于使用xsd.exe从XML Schema生成类的问题,以及如何预先处理模式(通常使用XSLT)来解决生成之前的一些棘手问题的建议。 我的问题是,是否可以构建一个100%符合XML Schema的C#代码生成器。 xsd.exe的问题仅仅是它的实现问题,还是它们指向XML Schema和C#之间的根本不一致?

特别是 ,我对如何将XML Schema中的概念映射到C#感兴趣 – 哪些是可接受的映射,哪些映射是有争议的,是否存在本质上不可映射的XML Schema构造,是否存在未充分利用的C#构造? 是否存在可提供映射规则的合规性规范,以便可以实施和测试?

编辑:为了清楚起见,我完全清楚XML Schema不会为我提供完全实现的C#接口,我对它是否可以完全映射到C#类层次结构感兴趣。

编辑2:我添加了一笔小额奖金,因为我有兴趣获得更多细节。

编辑3:赏金仍然开放,但到目前为止走向stakx – 一个很好的答案,但主要是处理如何在XML Schema中复制C#结构,而不是相反。 虽然好的输入。

有趣的问题。 不久前,我想知道完全一样的事情。

我将展示一些我得到多远的例子。 我的演示将不完整(考虑到XML Schema规范相当全面),但它应该足以显示……

  • 可以xsd.exe (如果您在编写XML Schema时愿意遵守某些模式); 和
  • XML Schema允许无法用C#表示的类型声明 。 考虑到XML和C#是非常不同的语言,目的不同,这不应该是一个大惊喜。

在XML Schema中声明一个接口

可以使用复杂类型在XML Schema中定义C#接口。 例如:

     

对应得相当好:

 interface IFoo { string Bar { get; set; } int? Baz { get; set; } } 

这里的模式是抽象和命名(非匿名)复杂类型基本上是C#中接口的XML Schema等价物。

请注意映射的一些问题:

  • C#访问修饰符(如publicinternal等)无法在XML Schema中呈现。

  • 您无法在XML Schema中表达C#字段和属性之间的区别。

  • 您无法在XML Schema中定义方法。

  • 您也无法表达C# structclass之间的区别。 (XML Schema中只有类型,它大致对应于.NET值类型;但它们在XML Schema中比复杂类型更受限制。)

  • usage="optional"usage="optional"可用于映射可空类型。 在XML Schema中,您可以将字符串属性定义为可选。 转换到C#时,会发生一些转换损失:由于string是引用类型,因此不能将其声明为可为空(因为默认情况下它已经可以为空)。

  • XML Schema还允许usage="prohibited" 。 这也是无法用C#表达的东西,或者至少是以一种不错的方式表达的(AFAIK)。

  • 根据我的实验,似乎xsd.exe 永远不会从抽象复杂类型生成C#接口; 它将与abstract class es保持一致。 (我猜这是为了让翻译逻辑保持相当简单。)

声明抽象类

抽象类可以与接口非常相似地完成:

   ...   

在这里,您定义一个abstract属性设置为true的元素,并在其中嵌入一个匿名复杂类型。

这对应于C#中的以下类型声明:

 abstract class FooBase { ... } 

宣布课程

如上所述,但省略abstract="true"

声明实现接口的类

  ...   

这映射到:

 interface IFoo { ... } class Foo : IFoo { ... } 

也就是说,您既定义了命名的抽象复杂类型(接口),又定义了具有该类型的命名元素。

  • 请注意,上面的C#代码段包含...两次,而XML Schema代码段只有一个... 怎么会?

    因为您无法定义方法(代码),并且因为您也无法指定访问修饰符,所以您不需要使用XML Schema中的元素“实现”复杂类型。 复杂类型的“实现”与原始声明相同。 如果复杂类型定义了某些属性,则这些属性只会在C#接口实现中映射到自动属性。

在XML Schema中表达inheritance关系

XML Schema中的类和接口inheritance可以通过类型扩展和元素替换组的组合来定义:

               

这映射到:

 class Base { bool Foo { get; set; } } class Derived : Base { string Bar { get; set; } } 

注意:

  • 我们再次使用命名复杂类型。 但这一次,他们没有定义abstract="true" ,因为我们没有定义任何C#接口类型。

  • 注意引用:Element DerivedBase的替换组中; 同时,复杂类型derived是复杂类型base的扩展。 DerivedDerived类型, Base有类型base

  • 非抽象的命名复杂类型在C#中没有直接对应的。 它们不是类,因为它们不能被实例化(在XML中, 元素 ,而不是类型 ,与F#中的值构造函数或C#中的对象实例化具有大致相同的function); 它们都不是真正的接口,因为它们不是抽象的。

我在答案中没有涉及的一些事情

  • 展示如何在XML Schema中声明实现多个接口的C#类类型。

  • 显示XML Schema中的复杂内容如何映射到C#(我首先猜测C#中根本没有对应关系;至少在一般情况下不是这样)。

  • enum (它们通过enumeration来限制简单类型,在XML Schema中实现,顺便说一下。)

  • const字段(这些字段可能映射到具有fixed值的属性)。

  • 如何将xsd:choicexsd:sequence映射到C#; 如何正确地将IEnumerableICollectionIListIDictionary映射到XML Schema?

  • XML Schema简单类型,听起来像是.NET值类型的相应概念; 但是受到更多限制并且有不同的目的。

还有很多我没有展示过的东西,但到现在为止你可能会看到我的例子背后的基本模式。

要正确地完成所有这些操作,必须系统地完成XML Schema规范,并查看其中提到的每个概念如何最好地映射到C#。 (可能没有单一的最佳解决方案,但有几种替代方案。)但我明确表示只展示几个有趣的例子。 我希望这仍然足够丰富!

这不是代码生成的限制。 这是XML模式不描述类。 它描述了XML,这是另一回事。

结果是XML Schema和C#类,Java类或任何其他类之间存在“阻抗不匹配”。 这两者并不等同,也不应该是等同的。