Сериализация общих свойств - PullRequest
9 голосов
/ 11 февраля 2011

Может кто-нибудь объяснить мне, почему этот первый пример будет сериализован в XML, а второй выдаст ошибки времени выполнения при попытке преобразовать все типы друг в друга? Если я удаляю атрибуты XmlElement из второго примера, он будет сериализован, но имя элемента XML будет неправильным («Элемент» вместо того, который указан для его типа). Первый фрагмент был сгенерирован из инструмента XSD с использованием файла схемы.

Еще лучше, есть ли способ заставить это работать? Я бы предпочел использовать универсальные типы, которые преобразуются в / из объектов. Это делает код намного чище. Явное приведение объектов показывает, что в вашем дизайне есть проблема.

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; }
    }
}

Это не будет сериализовано.

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; }
    }
}

И для дальнейшего разъяснения я попытался указать все дополнительные типы при создании объекта XmlSerializer, и это не помогает.

Это исключение, которое выдается:

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

Это имеет смысл с универсальным типом, видя, как тип является специфическим ограниченным во время компиляции. Но, увидев, как это работает со ссылкой на объект, на мой взгляд, оно должно работать и с универсальным типом.

Ответы [ 3 ]

2 голосов
/ 11 февраля 2011

Я думаю, что страница ошибки компилятора CS0029 на MSDN предоставляет информацию, которую вы ищете.

Исходя из того, как я читаю эту статью, ваш первый пример работает, потому что в вашем классе не происходит конвертация. Поскольку ваша простота распространяется вокруг Object, не требуется никакого преобразования, и не генерируются ошибки компилятора.

Во втором примере тип неизвестен до времени выполнения. Указывая несколько атрибутов XmlElement, компилятор считает, что все эти типы должны быть взаимозаменяемыми. Однако, поскольку вы не предоставили для них явных преобразований, компилятор обеспокоен тем, что преобразование между двумя типами может быть сужающим преобразованием, и выдает ошибку.

2 голосов
/ 11 февраля 2011

Вы смотрели страницу Generics FAQ под вопросом "Как сериализовать общие типы"?Это может помочь вам.

0 голосов
/ 12 февраля 2011

Единственный способ иметь разные сериализованные элементы для разных типов - это использовать object или IXmlSerializable.

К сожалению, XmlSerializer не может получить доступ к закрытым свойствам. Таким образом, экспонирование элемента как object через второе свойство public позволяет сериализовать. Я бы не стал использовать его в реальных ситуациях:

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

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