Сериализация абстрактных классов в XML с производными классами. System.InvalidOperationException ‹Class xmlns =" ​​/ ›не ожидалось

Я делаю приложение для гостиницы в качестве школьного проекта, и мне кажется, что это не работает. У меня есть абстрактный класс Arrangementen и 3 производных класса.

FamilieArrangementen: StandaardArrangementen StandaardArrangementen: Arrangementen LuxeArrangementen: Arrangementen

Каждый раз, когда я десериализую XML-файл, я получаю исключение System.InvalidOperationException ‹StandaardArrangement xmlns =" ​​/> не ожидалось.

Я искал в Интернете ответ и полагаю, что это что-то с пространством имен XmlRoot или XmlInclude работает неправильно

Какие-либо предложения?

Это мой код

абстрактный класс Arrangementen

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable()]
    [XmlInclude(typeof(FamilieArrangement))]
    [XmlInclude(typeof(StandaardArrangement))]
    [XmlInclude(typeof(LuxeArrangement))]
    public abstract class Arrangement: ICloneable
    {
    ...
    }
}

class FamilieArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class FamilieArrangement : StandaardArrangement
    {
    ...
    }
}

класс StandaardArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class StandaardArrangement : Arrangement
    {
    ...
    }
}

класс LuxeArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class LuxeArrangement : Arrangement
    {
    ...
    }
}

Код сериализации

internal void WriteArrangement(Arrangement ar, string path)
{
    using (FileStream bestand = File.Open(path, FileMode.OpenOrCreate))
    {         
        XmlSerializer xmls = new XmlSerializer(ar.GetType());
        xmls.Serialize(bestand, ar);
    }
}

Код десериализации

internal Arrangement ReadArrangement(string path)
{
    if (File.Exists(path))
    {
        using (FileStream bestand = File.Open(path, FileMode.OpenOrCreate))
        {    
            try
            {
                xmls = new XmlSerializer(typeof(Arrangement));
                Arrangement ar = (Arrangement) xmls.Deserialize(bestand);
                bestand.Close();
                return ar;
            }
            catch (Exception er)
            {
                MessageBox.Show("" + er.GetBaseException());
            } 
            bestand.Close();       
        }
    }
    return null;
}

другая попытка (которая не сработала, но дала еще одну ошибку

internal Arrangement ReadArrangement(string pad)
        {
            if (File.Exists(pad))
            {
                using (FileStream bestand = File.Open(pad, FileMode.OpenOrCreate))
                {    
                    try
                    {
                        xmls = new XmlSerializer(typeof(Arrangement));
                        Arrangement ar = (Arrangement) xmls.Deserialize(bestand);

                        bestand.Close();
                        return ar;
                    }
                    catch (Exception )
                    {
                        try
                        {
                            xmls = new XmlSerializer(typeof(FamilieArrangement));
                            FamilieArrangement ar = (FamilieArrangement)xmls.Deserialize(bestand);

                            bestand.Close();
                            return ar;
                        }
                        catch (Exception)
                        {
                            try
                            {
                                xmls = new XmlSerializer(typeof(StandaardArrangement));
                                StandaardArrangement ar = (StandaardArrangement)xmls.Deserialize(bestand);

                                bestand.Close();
                                return ar;
                            }
                            catch (Exception er)
                            {
                                MessageBox.Show("" + er.GetBaseException());
                            } 
                        } 
                    } 

                    bestand.Close();       
                }
            }

            return null;
        }

файл Xml со StandaardArrangement

<?xml version="1.0"?>
<StandaardArrangement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AantalVolw xmlns="HotelLib.Overkoepelend.Arrangementen">2</AantalVolw>
  <Kamer xmlns="HotelLib.Overkoepelend.Arrangementen">
    <MaxAantal>4</MaxAantal>
    <Bezetting>
      <Tijdslot>
        <Aankomst>2013-12-28T10:18:21.4384129+01:00</Aankomst>
        <Vertrek>2013-12-31T10:18:21</Vertrek>
      </Tijdslot>
    </Bezetting>
  </Kamer>
  <KlantId xmlns="HotelLib.Overkoepelend.Arrangementen">d4d72906-7b04-46aa-9986-4f22b232fbd0</KlantId>
  <Tijdslot xmlns="HotelLib.Overkoepelend.Arrangementen">
    <Aankomst>2013-12-28T15:09:10.1152899+01:00</Aankomst>
    <Vertrek>2013-12-30T15:09:10.1152899+01:00</Vertrek>
  </Tijdslot>
  <Type xmlns="HotelLib.Overkoepelend.Arrangementen">standaard</Type>
  <MaaltijdType>halfpension</MaaltijdType>
  <Opties>
    <KamerOpties>kluis</KamerOpties>
    <KamerOpties>wifi</KamerOpties>
  </Opties>
</StandaardArrangement>

person Jacob Notte    schedule 28.12.2013    source источник
comment
Покажите свой код сериализации / десериализации.   -  person Ondrej Tucny    schedule 28.12.2013
comment
Боковое примечание: [Serializable] не применяется к сериализации XML.   -  person Ondrej Tucny    schedule 28.12.2013
comment
я знаю, но нам нужно создать файл XML и binairy   -  person Jacob Notte    schedule 28.12.2013
comment
Не могли бы вы также поделиться XML, который вы пытаетесь прочитать?   -  person bas    schedule 28.12.2013
comment
@JacobNotte попробовал ответить, мне нужно кормить мою маленькую девочку сейчас, вернусь позже, чтобы проверить, могу ли я помочь дальше   -  person bas    schedule 28.12.2013


Ответы (2)


Я вижу, что вы используете «.GetType» для разрешения определенного типа при сериализации, но вы принудительно вызываете деерсериализацию родительского типа, Arrangement. (как кто-то еще только что написал :))

Это вызывает ошибку. Как и при сериализации, у вас должен быть доступен явный тип; он не будет автоматически пробовать всех дочерних элементов для десериализации.

Простой ответ - запросить имя в строке xml.

Перед загрузкой XmlSerializer загрузите XmlDocument.

Возьмите это корневое имя из XmlDocument.DocumentElement.Name.

Используйте статический метод Type.GetType для имени строки для типа XmlSerializer.

http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.documentelement(v=vs.110).aspx

Type.GetType (namespace.a.b.ClassName) возвращает null

person Mike M    schedule 28.12.2013
comment
Звучит интересно! собираюсь попробовать это - person Jacob Notte; 28.12.2013
comment
Спасибо, @bas. Сообщите мне, как это происходит! - person Mike M; 28.12.2013
comment
Оно работает! Большое спасибо. У меня были проблемы с этим фрагментом кода в течение нескольких часов - person Jacob Notte; 28.12.2013
comment
Здорово! Рад слышать это. - person Mike M; 28.12.2013
comment
@JacobNotte Можете ли вы принять ответ, если он решит ваш вопрос? - person bas; 29.12.2013

Да, здесь есть несколько хитрых вещей. Прежде всего, вы пытаетесь прочитать определенный тип из XML (StandaardArrangement), в то время как ваш XmlSerializer имеет базовый тип Arrangement. Это то, что вызывает исключение, которое вы видите. XmlSerializer ожидает чтения типа Arrangement, а встречает StandaardArrangement.

Если вы измените свой читатель на

var xmls = new XmlSerializer(typeof(StandaardArrangement));

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

Я предполагаю, что это тоже не решение для вас, потому что у вас, вероятно, есть куча Arrangement объектов, хранящихся в XML, которые смешаны в одном файле XML (я полагаю?).

Я бы предложил класс, содержащий Collection из Arrangement объектов, которые вы читаете из XML.

В результате получится что-то вроде этого ... (не говоря уже о деталях, вы уловите)

Класс контейнера:

public class Arrangements
{
    [XmlArray("Arrangement")]
    [XmlArrayItem("StandaardArrangement", typeof(StandaardArrangement)]
    [XmlArrayItem("LuxeArrangement", typeof(LuxeArrangement)]
    public List<Arrangement> Arrangements
    {
        ...
    }
}

Опять же, я упустил много деталей, полагаю, вы можете заполнить пробелы.

HTH!

XML (опущены детали, чтобы дать представление, в любом случае вы, вероятно, уже понимаете, что я имею в виду):

person bas    schedule 28.12.2013
comment
XML-файл всегда будет содержать только 1 аранжировку типа Familie, Standaard или Luxe. Но есть ли возможность сохранить конкретный объект Familie, Standaard или LuxeArrangement как объект Arrangement? У меня был фрагмент кода с вашим первым предложением, которое я загрузю, но я не работал - person Jacob Notte; 28.12.2013
comment
@JacobNotte Ага, тогда я понимаю, как уже прокомментировал ответ Майка: я бы тоже выбрал его решение. Запросите содержимое XML и проверьте тип или Arrangement. PS: Я настоятельно рекомендую НЕ использовать обработку исключений, чтобы определить, какой тип у вас в руках. PPS: Я настоятельно рекомендую писать код на английском языке и никогда не использовать имена переменных и классов на голландском языке. - person bas; 28.12.2013
comment
В классах веб-разработки я кодирую на английском, но на уроках C # учитель по-прежнему кодирует на голландском. Когда я делаю свои собственные проекты, я буду писать код на английском :) - person Jacob Notte; 28.12.2013