para - remarks c#
¿Cuáles son los límites para la generación de código desde el esquema XML en C#? (2)
Interesante pregunta. No hace mucho tiempo, me preguntaba sobre exactamente lo mismo.
Voy a mostrar un par de ejemplos de lo lejos que he llegado. Mi demostración no estará completa (considerando que la especificación del esquema XML es bastante completa), pero debería ser suficiente para mostrar ...
- que puedes hacerlo mejor que
xsd.exe
(si estás dispuesto axsd.exe
ciertos patrones cuando escribes tu esquema XML); y - ese esquema XML permite declaraciones de tipo que no pueden expresarse en C # . Esto no debería ser una gran sorpresa, considerando que XML y C # son lenguajes muy diferentes con propósitos muy diferentes.
Declarar una interfaz en esquema XML
Las interfaces de C # se pueden definir en el esquema XML con tipos complejos. Por ejemplo:
<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>
corresponde bastante bien a:
interface IFoo
{
string Bar { get; set; }
int? Baz { get; set; }
}
El patrón aquí es que los tipos abstractos y con nombre (no anónimos) son básicamente el equivalente del esquema XML de las interfaces en C #.
Note algunos problemas con el mapeo:
Los modificadores de acceso de C # tales como
public
,internal
, etc. no pueden representarse en el esquema XML.No tiene forma de expresar la diferencia entre un campo C # y una propiedad en el esquema XML.
No puede definir métodos en el esquema XML.
Tampoco tiene forma de expresar la diferencia entre una
struct
C y unaclass
. (Simplemente hay tipos en el esquema XML, que se corresponden aproximadamente con los tipos de valores .NET; pero son mucho más restringidos en el esquema XML que los tipos complejos).El uso de
usage="optional"
se puede usar para asignar tipos anulables. En el esquema XML, podría definir un atributo de cadena como opcional. Al pasar a C #, se produce alguna pérdida en la traducción: como lastring
es un tipo de referencia, no se puede declarar como anulable (ya que es anulable de forma predeterminada).El esquema XML también permite el
usage="prohibited"
. De nuevo, esto es algo que no se puede expresar en C #, o al menos de manera agradable (AFAIK).De mis experimentos, parece que
xsd.exe
nunca generará interfaces C # a partir de tipos complejos abstractos; se mantendrá conabstract class
lugar. (Supongo que esto es para mantener la lógica de traducción razonablemente simple).
Declarando clases abstractas
Las clases abstractas se pueden hacer de manera muy similar a las interfaces:
<xsd:element name="FooBase" abstract="true">
<xsd:complexType>
...
</xsd:complexType>
</xsd:element>
Aquí, define un elemento con el atributo abstract
establecido en true
e incrusta un tipo complejo anónimo dentro de él.
Esto corresponde a la siguiente declaración de tipo en C #:
abstract class FooBase { ... }
Declarando clases
Como arriba, pero omita el abstract="true"
.
Declarar clases que implementan una interfaz.
<xsd:complexType name="IFoo" abstract="true">
...
</xsd:complexType>
<xsd:element name="Foo" type="IFoo" />
Esto se asigna a:
interface IFoo { ... }
class Foo : IFoo { ... }
Es decir, usted define tanto un tipo complejo abstracto con nombre (la interfaz) como un elemento con nombre con ese tipo.
Tenga en cuenta que el fragmento de código de C # anterior contiene
...
dos veces, mientras que el fragmento de esquema XML solo tiene uno...
¿Cómo?Debido a que no puede definir métodos (código), y porque tampoco puede especificar modificadores de acceso, no necesita "implementar" un tipo complejo con el elemento en el esquema XML. La "implementación" del tipo complejo sería idéntica a la declaración original. Si el tipo complejo define algunos atributos, estos simplemente se asignan a propiedades automáticas en una implementación de interfaz C #.
Expresando relaciones de herencia en esquema XML
La herencia de clase e interfaz en el esquema XML se puede definir a través de una combinación de extensiones de tipo y grupos de sustitución de elementos:
<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>
Esto se asigna a:
class Base
{
bool Foo { get; set; }
}
class Derived : Base
{
string Bar { get; set; }
}
Nota:
Nuevamente estamos usando tipos complejos nombrados. Pero esta vez, no están definidos
abstract="true"
, ya que no estamos definiendo ningún tipo de interfaz C #.Note las referencias: el Elemento
Derived
está en el grupo de sustitución deBase
; al mismo tiempo, el tipo complejoderived
es una extensión de labase
tipo complejo.Derived
tiene tipoderived
,Base
tiene tipobase
.Los tipos complejos nombrados que no son abstractos no tienen contrapartida directa en C #. No son clases, ya que no se pueden crear instancias (en XML, los elementos , no los tipos , tienen aproximadamente la misma función que los constructores de valores en F # o la creación de instancias de objetos en C #); Tampoco son realmente interfaces, ya que no se declaran abstractas.
Algunas cosas que no he cubierto en mi respuesta
Mostrar cómo se declararía, en el esquema XML, un tipo de clase C # que implementa varias interfaces.
Mostrar cómo el contenido complejo en el esquema XML se asigna a C # (lo primero que supongo es que no hay correspondencia en C # en absoluto; al menos no en el caso general).
enum
s. (Se realizan en el esquema XML mediante la restricción de un tipo simple a través de laenumeration
, por cierto).campos
const
en una clase (estos posiblemente se asignarían a atributos con un valorfixed
).Cómo asignar
xsd:choice
,xsd:sequence
a C #; ¿Cómo asignar correctamenteIEnumerable<T>
,ICollection<T>
,IList<T>
,IDictionary<TKey, TValue>
al esquema XML?Tipos simples de esquema XML, que suenan como si fueran el concepto correspondiente de tipos de valores .NET; pero son mucho más restringidos y tienen un propósito diferente.
Hay muchas más cosas que no he mostrado, pero a estas alturas es probable que pueda ver los patrones básicos detrás de mis ejemplos.
Para hacer todo esto correctamente, uno tendría que ir sistemáticamente a través de la especificación del Esquema XML y ver cómo cada concepto mencionado allí se asigna mejor a C #. (Quizás no haya una única solución mejor, sino varias alternativas). Pero explícitamente quise mostrar solo un par de ejemplos interesantes. Espero que todavía fuera lo suficientemente informativo!
He visto varias preguntas sobre problemas con la generación de clases a partir del esquema XML usando xsd.exe
, junto con sugerencias sobre cómo preprocesar el esquema (a menudo usando XSLT) para resolver algunos de los aspectos más complicados antes de la generación. Mi pregunta es si es posible construir un generador de código C # que sea 100% compatible con el esquema XML. ¿Son los problemas con xsd.exe
simplemente una cuestión de su implementación, o apuntan a una inconsistencia fundamental entre el esquema XML y C #?
En particular , estoy interesado en cómo asignar conceptos en el esquema XML a C #: ¿cuáles son las asignaciones aceptadas, cuáles son discutibles, hay construcciones de esquema XML que son intrínsecamente imposibles de asignar y hay construcciones de C # que están subutilizadas? ¿Existe una especificación de cumplimiento que proporcione reglas para el mapeo, de manera que pueda implementarse y probarse?
EDITAR: En aras de la claridad, soy plenamente consciente de que el Esquema XML no me proporcionará interfaces C # totalmente implementadas, me interesa saber si se puede asignar completamente a una jerarquía de clases C #.
EDIT 2: He añadido una pequeña recompensa, ya que estoy interesado en obtener un poco más de detalle.
EDIT 3: Bounty aún está abierto, pero hasta ahora se dirige hacia stakx: es una buena respuesta, pero se trata principalmente de cómo replicar las estructuras de C # en el esquema XML, en lugar de hacerlo al revés. Buena entrada sin embargo.
No es un límite para la generación de código. Es que el esquema XML no describe las clases. Describe XML, que es una cosa diferente.
El resultado es que hay una "falta de coincidencia de impedancia" entre el esquema XML y las clases de C #, o las clases de Java, o cualquier otro tipo de clases. Los dos no son equivalentes, y no están destinados a ser.