XmlSerializer - Wystąpił błąd odzwierciedlający typ

332

Korzystając z C # .NET 2.0, mam złożoną klasę danych, która ma [Serializable]atrybut. Tworzę XMLSerializerklasę i przekazuję ją do konstruktora:

XmlSerializer serializer = new XmlSerializer(typeof(DataClass));

Otrzymuję wyjątek z informacją:

Wystąpił błąd odzwierciedlający typ.

Wewnątrz klasy danych znajduje się inny obiekt złożony. Czy to również musi mieć ten [Serializable]atrybut, czy poprzez umieszczenie go na najwyższym obiekcie, czy rekurencyjnie stosuje go do wszystkich obiektów w środku?

leora
źródło

Odpowiedzi:

413

Spójrz na wewnętrzny wyjątek, który otrzymujesz. Powie ci, które pole / właściwość ma problem z serializacją.

Możesz wykluczyć pola / właściwości z serializacji XML, dekorując je [XmlIgnore]atrybutem.

XmlSerializernie używa tego [Serializable]atrybutu, więc wątpię, że to jest problem.

Lamar
źródło
11
Mój obiekt miał pole Uri, co spowodowało ten wyjątek; klasa Uri nie ma konstruktora bez parametrów. Dzięki za wskazówkę.
ford
10
Spotykałem się z tym przy wyszukiwaniu w Google - moim szczególnym problemem było posiadanie właściwości w mojej klasie „do serializacji” tak, jak IListbyło to konieczne List.
Paul Aldred-Bann
7
Jak patrzeć na „wewnętrzny wyjątek”?
David
7
lub dodaj „@ wyjątek” do zegarka
arolson101
19
Dzięki, ta odpowiedź pomogła mi. Początkowo spojrzałem na wewnętrzny wyjątek i właśnie zobaczyłem wzmiankę o głównej klasie. Ale zdałem sobie sprawę, że mogę zgłębić inne wyjątki od niepreferencji i ostatecznie, o 5 poziomów w dół, znalazłem problem. Miałem zajęcia, które były sprzeczne. Dzięki.
Louis van Tonder,
111

Pamiętaj, że serializowane klasy muszą mieć domyślne (tj. Bez parametrów) konstruktory. Jeśli w ogóle nie masz konstruktora, w porządku; ale jeśli masz konstruktor z parametrem, musisz również dodać domyślny.

Jeremy McGee
źródło
4
Dzięki za przypomnienie! Nienawidzę tego, że jest to błąd czasu wykonywania z niewielkim wyjaśnieniem.
Jared Updike,
Cały czas popełniam ten błąd. dzięki za przypomnienie, żebym użył konstruktora bez parametrów ^^
aZtraL-EnForceR
25

Miałem podobny problem i okazało się, że serializator nie potrafił rozróżnić dwóch klas o tej samej nazwie (jedna była podklasą drugiej). Wewnętrzny wyjątek wyglądał tak:

„Typy BaseNamespace.Class1” i „BaseNamespace.SubNamespace.Class1” oba używają nazwy typu XML „Class1” z przestrzeni nazw ”. Użyj atrybutów XML, aby określić unikalną nazwę XML i / lub przestrzeń nazw dla typu.

Gdzie BaseNamespace.SubNamespace.Class1 jest podklasą BaseNamespace.Class1.

Musiałem dodać atrybut do jednej z klas (dodałem do klasy podstawowej):

[XmlType("BaseNamespace.Class1")]

Uwaga: jeśli masz więcej warstw klas, musisz również dodać do nich atrybut.

Dennis Calla
źródło
To rozwiązało problem dla mnie, dziękuję, +1; Miałem podobne ustawienie z kilkoma obiektami Procesor *, każdy z klasą wewnętrzną Config. Środowisko wykonawcze nie było w stanie odróżnić SomeNS.Processor1.Config od SomeNS.Processor2.Config.
damix911
7

Pamiętaj również, że XmlSerializernie można serializować właściwości abstrakcyjnych. Zobacz moje pytanie tutaj (do którego dodałem kod rozwiązania) ..

Serializacja XML i typy dziedziczone

Rob Cooper
źródło
6

Najczęstsze powody przeze mnie:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members
Stefan Michev
źródło
5

Jeśli potrzebujesz obsługiwać określone atrybuty (np. Słownik lub dowolną klasę), możesz zaimplementować interfejs IXmlSerialiable , który zapewni większą swobodę kosztem bardziej szczegółowego kodowania .

public class NetService : IXmlSerializable
{
    #region Data

        public string Identifier = String.Empty;

        public string Name = String.Empty;

        public IPAddress Address = IPAddress.None;
        public int Port = 7777;

    #endregion

    #region IXmlSerializable Implementation

        public XmlSchema GetSchema() { return (null); }

        public void ReadXml(XmlReader reader)
        {
            // Attributes
            Identifier = reader[XML_IDENTIFIER];
            if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
            if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
        }

        public void WriteXml(XmlWriter writer)
        {
            // Attributes
            writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
            writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
            writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
        }

        private const string XML_IDENTIFIER = "Id";

        private const string XML_NETWORK_ADDR = "Address";

        private const string XML_NETWORK_PORT = "Port";

    #endregion
}

Jest ciekawy artykuł , który pokazuje elegancki sposób implementacji wyrafinowanego sposobu „rozszerzenia” XmlSerializer.


Artykuł mówi:

IXmlSerializable jest objęty oficjalną dokumentacją, ale dokumentacja stwierdza, że ​​nie jest przeznaczony do użytku publicznego i nie zawiera żadnych informacji poza tym. Oznacza to, że zespół programistów chciał zastrzec sobie prawo do modyfikowania, wyłączania, a nawet całkowitego usuwania tego haka rozszerzalności na drodze. Jednak dopóki jesteś gotów zaakceptować tę niepewność i poradzić sobie z możliwymi zmianami w przyszłości, nie ma żadnego powodu, aby nie móc z niej skorzystać.

Ponieważ to sugeruję zaimplementować własne IXmlSerializableklasy, aby uniknąć zbyt skomplikowanych implementacji.

... implementacja naszej XmlSerializerklasy niestandardowej za pomocą odbicia może być prosta .

Luca
źródło
4

Odkryłem, że klasy Dictionary w .Net 2.0 nie można serializować przy użyciu XML, ale dobrze serializuje, gdy używana jest serializacja binarna.

Znalazłem pracę wokół tutaj .

Charlie Salts
źródło
3

Niedawno dostałem to w częściowej klasie referencji internetowych podczas dodawania nowej właściwości. Klasa automatycznie wygenerowana dodawała następujące atrybuty.

    [System.Xml.Serialization.XmlElementAttribute(Order = XX)]

Musiałem dodać podobny atrybut z rzędem wyższym niż ostatni w sekwencji generowanej automatycznie i to mnie naprawiło.

LepardUK
źródło
3

Właśnie dostałem ten sam błąd i odkryłem, że IEnumerable<SomeClass>problemem była właściwość typu . Wygląda na to, że IEnumerablenie można go serializować bezpośrednio.

Zamiast tego można użyć List<SomeClass>.

jkokorian
źródło
2

Ja również myślałem, że atrybut Serializable musiał znajdować się na obiekcie, ale chyba, że ​​jestem kompletnym noob (jestem w trakcie sesji kodowania późno w nocy), następujące prace z SnippetCompiler :

using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;

public class Inner
{
    private string _AnotherStringProperty;
    public string AnotherStringProperty 
    { 
      get { return _AnotherStringProperty; } 
      set { _AnotherStringProperty = value; } 
    }
}

public class DataClass
{
    private string _StringProperty;
    public string StringProperty 
    { 
       get { return _StringProperty; } 
       set{ _StringProperty = value; } 
    }

    private Inner _InnerObject;
    public Inner InnerObject 
    { 
       get { return _InnerObject; } 
       set { _InnerObject = value; } 
    }
}

public class MyClass
{

    public static void Main()
    {
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
            TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
            DataClass clazz = new DataClass();
            Inner inner = new Inner();
            inner.AnotherStringProperty = "Foo2";
            clazz.InnerObject = inner;
            clazz.StringProperty = "foo";
            serializer.Serialize(writer, clazz);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

}

Wyobrażam sobie, że XmlSerializer używa refleksji nad właściwościami publicznymi.

Darren
źródło
1

Miałem sytuację, w której Zakon był taki sam dla dwóch elementów z rzędu

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]

.... trochę kodu ...

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]

Kiedy zmieniłem kod, aby zwiększyć kolejność o jeden dla każdej nowej właściwości w klasie, błąd zniknął.

Jeremy Brown
źródło
1

Otrzymałem ten sam błąd, gdy utworzyłem właściwość o typie danych - Type. Wystąpił błąd - wystąpił błąd odzwierciedlający typ. Ciągle sprawdzałem „InnerException” każdego wyjątku z doku debugowania i dostałem konkretną nazwę pola (która była Type) w moim przypadku. Rozwiązanie jest następujące:

    [XmlIgnore]
    public Type Type { get; set; }
Iqra.
źródło
0

Należy również pamiętać, że nie można serializować kontrolek interfejsu użytkownika i że każdy obiekt, który chcesz przekazać do schowka, musi być możliwy do serializacji, w przeciwnym razie nie będzie można go przekazać innym procesom.

Phil Wright
źródło
0

Miałem ten sam problem iw moim przypadku obiekt miał ReadOnlyCollection. Kolekcja musi implementować metodę Add, aby była możliwa do serializacji.

Curious Dev
źródło
To nie jest właściwa odpowiedź na pytanie. Jest jeszcze 15 odpowiedzi na to pytanie. Jeśli uważasz, że Twoja odpowiedź jest lepsza niż inne, powinieneś podać więcej szczegółów na jej temat. Zapewnienie niektórych fragmentów kodu i fragmentów wyjściowych zawsze pomaga użytkownikom. Przed opublikowaniem odpowiedzi rozważ przeczytanie -> stackoverflow.com/help/how-to-answer
Amit Phaltankar
0

Mam nieco inne rozwiązanie do wszystkich opisanych tutaj do tej pory, więc dla każdej przyszłej cywilizacji jest moja!

Zadeklarowałem typ danych „czas”, ponieważ pierwotny typ to a, TimeSpana następnie zmieniono na String:

[System.Xml.Serialization.XmlElementAttribute(DataType="time", Order=3)]

jednak faktyczny typ był łańcuchem

public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

przez usunięcie DateTypewłaściwości Xmlmożna serializować

[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}
chxzy
źródło
0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

Lub

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
źródło