Ответ 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 и посмотреть, как каждая концепция, упомянутая там, лучше всего подходит для С#. (Возможно, нет единственного лучшего решения, но несколько альтернатив.) Но я явно хотел показать только несколько интересных примеров. Надеюсь, это было достаточно информативно!