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#访问修饰符(如
public
,internal
等)无法在XML Schema中呈现。 -
您无法在XML Schema中表达C#字段和属性之间的区别。
-
您无法在XML Schema中定义方法。
-
您也无法表达C#
struct
和class
之间的区别。 (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
Derived
在Base
的替换组中; 同时,复杂类型derived
是复杂类型base
的扩展。Derived
有Derived
类型,Base
有类型base
。 -
非抽象的命名复杂类型在C#中没有直接对应的。 它们不是类,因为它们不能被实例化(在XML中, 元素 ,而不是类型 ,与F#中的值构造函数或C#中的对象实例化具有大致相同的function); 它们都不是真正的接口,因为它们不是抽象的。
我在答案中没有涉及的一些事情
-
展示如何在XML Schema中声明实现多个接口的C#类类型。
-
显示XML Schema中的复杂内容如何映射到C#(我首先猜测C#中根本没有对应关系;至少在一般情况下不是这样)。
-
enum
(它们通过enumeration
来限制简单类型,在XML Schema中实现,顺便说一下。) -
const
字段(这些字段可能映射到具有fixed
值的属性)。 -
如何将
xsd:choice
,xsd:sequence
映射到C#; 如何正确地将IEnumerable
,ICollection
,IList
,IDictionary
映射到XML Schema? -
XML Schema简单类型,听起来像是.NET值类型的相应概念; 但是受到更多限制并且有不同的目的。
还有很多我没有展示过的东西,但到现在为止你可能会看到我的例子背后的基本模式。
要正确地完成所有这些操作,必须系统地完成XML Schema规范,并查看其中提到的每个概念如何最好地映射到C#。 (可能没有单一的最佳解决方案,但有几种替代方案。)但我明确表示只展示几个有趣的例子。 我希望这仍然足够丰富!
这不是代码生成的限制。 这是XML模式不描述类。 它描述了XML,这是另一回事。
结果是XML Schema和C#类,Java类或任何其他类之间存在“阻抗不匹配”。 这两者并不等同,也不应该是等同的。