2011-02-11 11 views
9

¿Puede alguien explicarme por qué este primer ejemplo se serializará en XML, y el segundo arrojará errores de tiempo de ejecución al tratar de convertir todos los tipos entre sí? Si elimino los atributos XmlElement del segundo ejemplo, se serializará, pero el nombre del elemento XML será incorrecto ("Artículo" en lugar del especificado para ese tipo). El primer fragmento se generó a partir de la herramienta XSD utilizando el archivo de esquema.Serialización de propiedades genéricas

Mejor aún, ¿hay alguna manera de hacer que esto funcione? Preferiría usar tipos genéricos que emiten a/desde objetos. Hace un código mucho más limpio. Expulsar objetos explícitamente muestra que hay un problema en su diseño.

public partial class OAIPMHtype 
{ 
    private object itemsField; 

    [XmlElement("GetRecord", typeof(GetRecordType))] 
    [XmlElement("Identify", typeof(IdentifyType))] 
    [XmlElement("ListIdentifiers", typeof(ListIdentifiersType))] 
    [XmlElement("ListMetadataFormats", typeof(ListMetadataFormatsType))] 
    [XmlElement("ListRecords", typeof(ListRecordsType))] 
    [XmlElement("ListSets", typeof(ListSetsType))] 
    [XmlElement("error", typeof(OAIPMHerrorType))] 
    public object Item 
    { 
     get { return this.itemsField; } 
     set { this.itemsField = value; } 
    } 
} 

Esto no se serializará.

public class OaiPmh<T> 
{ 
    private T itemsField; 

    [XmlElement("GetRecord", typeof(GetRecordType))] 
    [XmlElement("Identify", typeof(IdentifyType))] 
    [XmlElement("ListIdentifiers", typeof(ListIdentifiersType))] 
    [XmlElement("ListMetadataFormats", typeof(ListMetadataFormatsType))] 
    [XmlElement("ListRecords", typeof(ListRecordsType))] 
    [XmlElement("ListSets", typeof(ListSetsType))] 
    [XmlElement("error", typeof(OAIPMHerrorType))] 
    public T Item 
    { 
     get { return itemsField; } 
     set { itemsField = value; } 
    } 
} 

Y para mayor aclaración, he tratado de especificar todos los tipos adicionales al crear el objeto XmlSerializer, y eso no ayuda.

Esta es la excepción que ha arrojado:

Unable to generate a temporary class (result=1). 
error CS0030: Cannot convert type 'ErrorRequest' to 'GetRecordRequest' 
error CS0030: Cannot convert type 'ErrorRequest' to 'ListRecordsRequest' 
error CS0030: Cannot convert type 'ErrorRequest' to 'IdentityRequest' 
error CS0030: Cannot convert type 'ErrorRequest' to 'ListSetsRequest' 
error CS0030: Cannot convert type 'ErrorRequest' to 'ListIdentifiersRequest' 
error CS0030: Cannot convert type 'ErrorRequest' to 'ListMetadataFormatsRequest' 
error CS0029: Cannot implicitly convert type 'ListSetsRequest' to 'ErrorRequest' 
error CS0029: Cannot implicitly convert type 'ListIdentifiersRequest' to 'ErrorRequest' 
error CS0029: Cannot implicitly convert type 'ListMetadataFormatsRequest' to 'ErrorRequest' 
error CS0029: Cannot implicitly convert type 'GetRecordRequest' to 'ErrorRequest' 
error CS0029: Cannot implicitly convert type 'ListRecordsRequest' to 'ErrorRequest' 
error CS0029: Cannot implicitly convert type 'IdentityRequest' to 'ErrorRequest 

'

En cierto modo tiene sentido con el tipo genérico, viendo cómo el tipo es consolidado específico en tiempo de compilación. Pero al ver cómo funciona con una referencia de objeto, en mi opinión, también debería funcionar con el tipo genérico.

+0

¿Cuál es la excepción lanzada? –

+0

Gracias, voy a editar. – MonkeyWrench

+0

¿Qué es 'ErrorRequest'? –

Respuesta

2

Creo que el CS0029 compiler error page on MSDN proporciona la información que está buscando.

Según cómo leo este artículo, su primer ejemplo funciona porque no hay conversión en su clase. Debido a que explicity está pasando por un Object no hay conversión que deba suceder y no se lanzan errores del compilador.

En el segundo ejemplo, el tipo no se conoce hasta el tiempo de ejecución. Al especificar múltiples atributos de XmlElement, el compilador cree que todos estos tipos deben ser intercambiables. Sin embargo, dado que no ha proporcionado conversiones explícitas para estos, al compilador le preocupa que una conversión entre los dos tipos pueda ser una conversión de reducción y arroje el error.

+0

Acepto que ese es el problema, pero estoy confundido sobre por qué los atributos de XmlElement funcionan en la propiedad del objeto. La propiedad define el elemento Xml en la salida serializada. ¿Alguna de idea de cómo arreglarlo? – MonkeyWrench

+0

Sospecho que el compilador está creando una clase para cada atributo XmlElement que está especificando para que, en tiempo de ejecución, los datos de entrada se puedan serializar en esos diferentes formularios. No estoy seguro de que encuentre una solución para ello porque para permitir la serialización entre tipos, el compilador necesita conocer ambos tipos en tiempo de compilación. ... pero no estoy 100% seguro. – pmartin

+0

Todas esas clases existen, simplemente no las agregué al fragmento de código ya que son muy simples y extrañas al ejemplo. – MonkeyWrench

2

¿Ha consultado la página Generics FAQ en la pregunta "¿Cómo serializo los tipos genéricos?" Puede ayudarte.

0

La única manera de tener diferentes elementos serializados para diferentes tipos es usar object o IXmlSerializable.

Desafortunadamente, el XmlSerializer no puede acceder a propiedades no públicas. Por lo tanto, exponer el artículo como object a través de una segunda propiedad pública permite la serialización. No lo usaría en situaciones reales, sin embargo:

[XmlElement("GetRecord", typeof(GetRecordType))] 
[XmlElement("Identify", typeof(IdentifyType))] 
public object ItemSerializer 
{ 
    get { return this.Item; } 
    set { this.Item = (T)value; } 
} 

[XmlIgnore] 
public T Item 
//... 
+0

Pero eso es exactamente lo que trato de evitar. No debería haber necesidad de utilizar iXmlSerializable o una propiedad de objeto en este escenario. – MonkeyWrench

Cuestiones relacionadas