Подтвердить что ты не робот

Каковы пределы генерации кода из XML-схемы в С#?

Я видел несколько вопросов относительно проблем с генерацией классов из XML-схемы с помощью xsd.exe, а также предложения о том, как предварительно обработать схему (часто используя XSLT), чтобы решить некоторые из более сложных аспектов до генерации. Мой вопрос заключается в том, можно ли построить генератор кода С#, который на 100% совместим с XML-схемой. Являются ли проблемы с xsd.exe просто вопросом его реализации или они указывают на фундаментальную несогласованность между XML Schema и С#?

В частности,, я заинтересован в том, как сопоставить понятия в XML-схеме с С# - каковы принятые сопоставления, какие отображения являются дискуссионными, существуют ли конструкции XML Schema, которые по своей сути неотменяемы и существуют ли конструкции С#, которые недостаточно используются? Существует ли спецификация соответствия, которая обеспечивала бы правила для сопоставления, чтобы ее можно было реализовать и протестировать?

EDIT: Для ясности я полностью понимаю, что XML Schema не предоставит мне полностью реализованные интерфейсы С#, меня интересует, может ли она полностью отображаться в иерархии классов С#.

EDIT 2: Я добавил небольшую награду, так как мне интересно узнать немного больше.

EDIT 3: Bounty все еще открыт, но пока идет в сторону stakx - хороший ответ, но в основном касается того, как реплицировать структуры С# в XML-схеме, а не наоборот. Хороший ввод, хотя.

4b9b3361

Ответ 1

Интересный вопрос. Не так давно мне было интересно, что именно то же самое.

Я покажу пару примеров того, как далеко я добрался. Моя демонстрация не будет полной (учитывая, что спецификация XML-схемы достаточно полная), но этого достаточно, чтобы показать...

  • что вы можете сделать лучше, чем xsd.exe (если вы захотите придерживаться определенных шаблонов при написании своей XML-схемы); и
  • что XML-схема позволяет объявлять типы, которые не могут быть выражены в С#. Это не должно стать большим сюрпризом, учитывая, что XML и С# - это очень разные языки с совершенно разными целями.

Объявление интерфейса в XML-схеме

Интерфейсы С# могут быть определены в XML-схеме со сложными типами. Например:

<xsd:complexType name="IFoo" abstract="true">
  <xsd:attribute name="Bar" type="xsd:string" use="required" />
  <xsd:attribute name="Baz" type="xsd:int" use="optional" />
</xsd:complexType>

достаточно хорошо соответствует:

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

Образец здесь состоит в том, что абстрактные и именованные (не анонимные) сложные типы в основном эквивалентны XML-схемы интерфейсов в С#.

Обратите внимание на некоторые проблемы с отображением:

  • Модификаторы доступа С#, такие как public, internal и т.д., не могут быть отображены в XML-схеме.

  • У вас нет способа выразить разницу между полем С# и свойством в XML-схеме.

  • Вы не можете определять методы в XML-схеме.

  • У вас также нет способа выразить разницу между С# struct и class. (Там просто типы XML-схемы, которые примерно соответствуют типам значений .NET, но они гораздо более ограничены в XML-схеме, чем сложные типы.)

  • Использование usage="optional" может использоваться для отображения типов с нулевым значением. В XML-схеме вы можете определить атрибут строки как необязательный. Перейдя на С#, возникает некоторая потеря в переводе: поскольку string является ссылочным типом, он не может быть объявлен как nullable (поскольку он по умолчанию уже обнуляется).

  • XML-схема также позволяет usage="prohibited". Это снова то, что не может быть выражено в С# или, по крайней мере, красивым способом (AFAIK).

  • Из моих экспериментов кажется, что xsd.exe никогда не будет генерировать интерфейсы С# из абстрактных сложных типов; он останется с abstract class es. (Я предполагаю, что это должно сделать логику перевода достаточно простой.)

Объявление абстрактных классов

Абстрактные классы могут выполняться очень точно так же, как и интерфейсы:

<xsd:element name="FooBase" abstract="true">
  <xsd:complexType>
    ...
  </xsd:complexType>
</xsd:element>

Здесь вы определяете элемент с атрибутом abstract, установленным на true, и вставляете в него анонимный сложный тип.

Это соответствует следующему объявлению типа в С#:

abstract class FooBase { ... }

Объявление классов

Как и выше, но опустите abstract="true".

Объявление классов, реализующих интерфейс

<xsd:complexType name="IFoo" abstract="true">
  ...
</xsd:complexType>

<xsd:element name="Foo" type="IFoo" />

Это соответствует:

interface IFoo { ... }

class Foo : IFoo { ... }

То есть вы определяете как именованный, абстрактный сложный тип (интерфейс), так и именованный элемент с этим типом.

  • Обратите внимание, что фрагмент кода С# выше содержит ... дважды, а фрагмент XML-схемы имеет только один .... Почему?

    Поскольку вы не можете определить методы (код) и потому, что вы также не можете указать модификаторы доступа, вам не нужно "внедрять" сложный тип с элементом в XML-схеме. "Реализация" сложного типа будет идентична первоначальной декларации. Если сложный тип определяет некоторые атрибуты, они просто сопоставляются с автоматическими свойствами в реализации интерфейса С#.

Выражение отношений наследования в XML-схеме

Наследование классов и интерфейсов в XML-схеме может быть определено с помощью комбинации расширений типов и групп подстановки элементов:

<xsd:element name="Base" type="base" />
<xsd:element name="Derived" substitutionGroup="Base" type="derived" />
                       <!-- ^^^^^^^^^^^^^^^^^^^^^^^^ -->

<xsd:complexType name="base">
  <xsd:attribute name="Foo" type="xsd:boolean" use="required" />
</xsd:complexType>

<xsd:complexType name="derived">
  <xsd:complexContent>
    <xsd:extension base="base">  <!-- !!! -->
      <xsd:attribute name="Bar" type="xsd:string" use="required" />
    </xsd:extension>
  </xsd:complexContent>
</xsd:complexType>

Это соответствует:

class Base
{
    bool Foo { get; set; }
}

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

Примечание:

  • Мы снова используем именованные сложные типы. Но на этот раз они не определены abstract="true", так как мы не определяем тип интерфейса С#.

  • Обратите внимание на ссылки: Элемент Derived находится в группе подстановки Base; в то же время сложный тип Derived является расширением сложного типа Base. Derived имеет тип Derived, Base имеет тип Base.

  • Именованные сложные типы, которые не являются абстрактными, не имеют прямого аналога в С#. Они не являются классами, поскольку они не могут быть созданы (в XML, элементы, а не типы, имеют примерно ту же функцию, что и конструкторы значений в F # или экземпляре объекта в С#); они также не являются интерфейсами, поскольку они не объявлены абстрактными.

Некоторые вещи, которые я не затронул в своем ответе

  • Отображение того, как можно было бы объявить в XML-схеме тип класса С#, который реализует несколько интерфейсов.

  • Показывает, как сложный контент в XML-схеме сопоставляется с С# (прежде всего я предполагаю, что нет никакого соответствия в С# вообще, по крайней мере, не в общем случае).

  • enum s. (Они реализованы в XML-схеме, ограничив простой тип с помощью enumeration, btw.)

  • const поля в классе (они, возможно, будут сопоставляться с атрибутами со значением fixed).

  • Как сопоставить xsd:choice, xsd:sequence с С#; Как правильно сопоставить IEnumerable<T>, ICollection<T>, IList<T>, IDictionary<TKey, TValue> с XML-схемой?

  • Простые типы XML-схем, которые звучат так, как будто они представляют собой концепцию типов значений .NET; но гораздо более ограничены и имеют другую цель.

Есть много других вещей, которые я еще не показывал, но теперь вы можете увидеть основные шаблоны моих примеров.

Чтобы сделать все это правильно, нужно было бы систематически пройти спецификацию XML Schema и посмотреть, как каждая концепция, упомянутая там, лучше всего подходит для С#. (Возможно, нет единственного лучшего решения, но несколько альтернатив.) Но я явно хотел показать только несколько интересных примеров. Надеюсь, это было достаточно информативно!

Ответ 2

Это не предел генерации кода. Это то, что XML-схема не описывает классы. Он описывает XML, что совсем другое.

В результате существует "несоответствие импеданса" между классами XML Schema и С# или классами Java или любыми другими классами. Эти два не эквивалентны и не предназначены.