Can someone explain to me why this first example will serialize into XML, and the second will throw开发者_开发知识库 runtime errors about trying to convert all of the types to each other? If I remove the XmlElement
attributes from the second example, it will serialize but the XML element name will be wrong ( "Item" instead of the one specified for its type). The first snippet was generated from the XSD tool using the schema file.
Better yet, is there a way to get this to work? I would much prefer to use generic types that casting to/from objects. It makes for much cleaner code. Explicitly casting objects shows there's a problem in your design.
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; }
}
}
This will not serialize.
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; }
}
}
And for further clarification, I have tried specifying all the extra types when creating the XmlSerializer
object, and that does not help.
This is the exception that's thrown:
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
'
It kind of makes sense with the generic type, seeing how the type is specific bound at compile time. But seeing how it works with an object reference, in my mind it should also work with the generic type.
I think that the CS0029 compiler error page on MSDN provides the information you're looking for.
Based on how I read this article, your first example works because there is no conversion happening in your class. Because you explicity are passing around an Object
there is no conversion that needs to happen and no compiler errors are thrown.
In the second example the type is not known until run time. By specifying multiple XmlElement attributes the compiler thinks that all of these types must be interchangeable. However, since you haven't provided explicit conversions for these the compiler is concerned that a conversion between the two types could be a narrowing conversion and throws the error.
Have you looked at the Generics FAQ page under the "How Do I Serialize Generic Types" question? It may help you out.
The only way to have different serialized elements for different types is to use object
or IXmlSerializable
.
Unfortunatelly the XmlSerializer cannot access non-public properties. So exposing the item as an object
via a second public property allows serialization. I would not use it in real situations, though:
[XmlElement("GetRecord", typeof(GetRecordType))]
[XmlElement("Identify", typeof(IdentifyType))]
public object ItemSerializer
{
get { return this.Item; }
set { this.Item = (T)value; }
}
[XmlIgnore]
public T Item
//...
精彩评论