XmlSerializer - Es ist ein Fehler aufgetreten, der den Typ widerspiegelt

332

Mit C # .NET 2.0 habe ich eine zusammengesetzte Datenklasse, die das [Serializable]Attribut enthält. Ich erstelle eine XMLSerializerKlasse und übergebe diese an den Konstruktor:

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

Ich bekomme eine Ausnahme mit den Worten:

Es gab einen Fehler, der den Typ widerspiegelte.

Innerhalb der Datenklasse befindet sich ein weiteres zusammengesetztes Objekt. Muss das [Serializable]Attribut auch vorhanden sein oder wird es rekursiv auf alle darin enthaltenen Objekte angewendet, indem es sich auf dem obersten Objekt befindet?

Leora
quelle

Antworten:

413

Schauen Sie sich die innere Ausnahme an, die Sie bekommen. Hier erfahren Sie, für welches Feld / welche Eigenschaft Probleme beim Serialisieren auftreten.

Sie können Felder / Eigenschaften von der XML-Serialisierung ausschließen, indem Sie sie mit dem [XmlIgnore]Attribut dekorieren .

XmlSerializerverwendet das [Serializable]Attribut nicht, daher bezweifle ich, dass dies das Problem ist.

Lamar
quelle
11
Mein Objekt hatte ein Uri-Feld, was diese Ausnahme verursachte. Die Uri-Klasse hat keinen parameterlosen Konstruktor. Danke für den Tipp.
Ford
10
Kam mit einer Google-Suche darauf - mein besonderes Problem war, dass eine Eigenschaft in meiner Klasse "Serialisiert werden sollte" so war, wie IListes sein musste List.
Paul Aldred-Bann
7
Wie sieht man eine "innere Ausnahme"?
David
7
oder fügen Sie '@exception' zu einer Uhr hinzu
arolson101
19
Danke, diese Antwort hat mir geholfen. Ich schaute zunächst auf die innere Ausnahme und sah nur die Erwähnung der Hauptklasse. Aber mir wurde klar, dass ich einen Drilldown in die inneren Ausnahmen der Innrexceptions durchführen konnte, und schließlich, 5 Level tiefer, fand ich das Problem. Ich hatte Klassen, die widersprüchlich waren. Vielen Dank.
Louis van Tonder
111

Denken Sie daran, dass serialisierte Klassen Standardkonstruktoren (dh parameterlose Konstruktoren) haben müssen. Wenn Sie überhaupt keinen Konstruktor haben, ist das in Ordnung. Wenn Sie jedoch einen Konstruktor mit einem Parameter haben, müssen Sie auch den Standardkonstruktor hinzufügen.

Jeremy McGee
quelle
4
Danke für die Erinnerung! Ich hasse es, dass dies ein Laufzeitfehler mit wenig Erklärung ist.
Jared Updike
Ich mache diesen Fehler immer und immer wieder.
Vielen
25

Ich hatte ein ähnliches Problem und es stellte sich heraus, dass der Serializer nicht zwischen zwei Klassen mit demselben Namen unterscheiden konnte (eine war eine Unterklasse der anderen). Die innere Ausnahme sah folgendermaßen aus:

'Typ BaseNamespace.Class1' und 'BaseNamespace.SubNamespace.Class1' verwenden beide den XML-Typnamen 'Class1' aus dem Namespace ''. Verwenden Sie XML-Attribute, um einen eindeutigen XML-Namen und / oder Namespace für den Typ anzugeben.

Wobei BaseNamespace.SubNamespace.Class1 eine Unterklasse von BaseNamespace.Class1 ist.

Was ich tun musste, war ein Attribut zu einer der Klassen hinzuzufügen (ich fügte der Basisklasse hinzu):

[XmlType("BaseNamespace.Class1")]

Hinweis: Wenn Sie mehr Klassenebenen haben, müssen Sie diesen ebenfalls ein Attribut hinzufügen.

Dennis Calla
quelle
Dies hat das Problem für mich behoben, danke, +1; Ich hatte eine ähnliche Einstellung mit mehreren Processor * -Objekten, jedes mit einer Config-Innenklasse. Die Laufzeit konnte nicht zwischen SomeNS.Processor1.Config und SomeNS.Processor2.Config unterscheiden.
Damix911
7

Beachten Sie auch, dass XmlSerializerabstrakte Eigenschaften nicht serialisiert werden können. Siehe meine Frage hier (zu der ich den Lösungscode hinzugefügt habe).

XML-Serialisierung und geerbte Typen

Rob Cooper
quelle
6

Die häufigsten Gründe von mir:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members
Stefan Michev
quelle
5

Wenn Sie bestimmte Attribute (z. B. Dictionary oder eine beliebige Klasse) verarbeiten müssen, können Sie die IXmlSerialiable- Schnittstelle implementieren , die Ihnen mehr Freiheit auf Kosten einer ausführlicheren Codierung ermöglicht .

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
}

Es gibt einen interessanten Artikel , der eine elegante Methode zum Implementieren einer ausgeklügelten Methode zum "Erweitern" des XmlSerializers zeigt.


Der Artikel sagt:

IXmlSerializable wird in der offiziellen Dokumentation behandelt. In der Dokumentation wird jedoch angegeben, dass es nicht für die öffentliche Verwendung bestimmt ist und darüber hinaus keine Informationen enthält. Dies weist darauf hin, dass das Entwicklungsteam sich das Recht vorbehalten wollte, diesen Erweiterungshaken später zu ändern, zu deaktivieren oder sogar vollständig zu entfernen. Solange Sie jedoch bereit sind, diese Unsicherheit zu akzeptieren und sich mit möglichen Änderungen in der Zukunft zu befassen, gibt es keinen Grund, warum Sie sie nicht nutzen können.

Aus diesem Grund empfehle ich, eigene IXmlSerializableKlassen zu implementieren , um zu komplizierte Implementierungen zu vermeiden.

... es könnte einfach sein, unsere benutzerdefinierte XmlSerializerKlasse mithilfe von Reflektion zu implementieren .

Luca
quelle
4

Ich habe festgestellt, dass die Dictionary-Klasse in .Net 2.0 nicht mit XML serialisierbar ist, sondern bei Verwendung der binären Serialisierung gut serialisiert werden kann.

Ich habe hier eine Arbeit gefunden .

Charlie Salts
quelle
3

Ich habe dies kürzlich in einer Webreferenz-Teilklasse erhalten, als ich eine neue Eigenschaft hinzugefügt habe. Die automatisch generierte Klasse fügte die folgenden Attribute hinzu.

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

Ich musste ein ähnliches Attribut mit einer Reihenfolge hinzufügen, die höher als die letzte in der automatisch generierten Sequenz ist, und dies hat es für mich behoben.

LepardUK
quelle
3

Ich habe gerade den gleichen Fehler erhalten und festgestellt, dass eine Eigenschaft vom Typ IEnumerable<SomeClass>das Problem war. Es scheint, dass IEnumerablenicht direkt serialisiert werden kann.

Stattdessen könnte man verwenden List<SomeClass>.

jkokorian
quelle
2

Ich dachte auch, dass das Serializable-Attribut auf dem Objekt sein muss, aber wenn ich kein vollständiger Noob bin (ich bin mitten in einer Late-Night-Codierungssitzung), funktioniert das Folgende vom 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();
        }
    }

}

Ich würde mir vorstellen, dass der XmlSerializer die öffentlichen Eigenschaften reflektiert.

Darren
quelle
1

Ich hatte eine Situation, in der der Orden für zwei Elemente hintereinander gleich war

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

.... etwas Code ...

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

Als ich den Code so änderte, dass die Reihenfolge für jede neue Eigenschaft in der Klasse um eins erhöht wurde, verschwand der Fehler.

Jeremy Brown
quelle
1

Ich habe den gleichen Fehler erhalten, als ich eine Eigenschaft mit einem Datentyp erstellt habe - Type. Daraufhin wurde ein Fehler angezeigt. Es gab einen Fehler, der den Typ widerspiegelte. Ich überprüfte ständig die 'InnerException' jeder Ausnahme aus dem Debug-Dock und bekam den spezifischen Feldnamen (der Typein meinem Fall war ). Die Lösung lautet wie folgt:

    [XmlIgnore]
    public Type Type { get; set; }
Iqra.
quelle
0

Beachten Sie außerdem, dass Sie Steuerelemente der Benutzeroberfläche nicht serialisieren können und dass jedes Objekt, das Sie in die Zwischenablage übergeben möchten, serialisierbar sein muss, da es sonst nicht an andere Prozesse übergeben werden kann.

Phil Wright
quelle
0

Ich habe die NetDataSerialiserKlasse verwendet, um meine Domänenklassen zu serialisieren. NetDataContractSerializer-Klasse .

Die Domänenklassen werden von Client und Server gemeinsam genutzt.

Peter Mortensen
quelle
0

Ich hatte das gleiche Problem und in meinem Fall hatte das Objekt eine ReadOnlyCollection. Eine Sammlung muss die Add-Methode implementieren, um serialisierbar zu sein.

Neugieriger Dev
quelle
Dies ist keine richtige Antwort auf die Frage. Es gibt bereits 15 weitere Antworten auf diese Frage. Wenn Sie der Meinung sind, dass Ihre Antwort besser ist als die der anderen, sollten Sie weitere Details dazu angeben. Das Bereitstellen von Code- und Ausgabeausschnitten hilft Benutzern immer. Bevor Sie Ihre Antworten veröffentlichen, lesen Sie bitte
Amit Phaltankar
0

Ich habe eine etwas andere Lösung als alle hier bisher beschriebenen, also für jede zukünftige Zivilisation hier meine!

Ich hatte einen Datentyp von "Zeit" deklariert, da der ursprüngliche Typ a war, TimeSpanund anschließend in a geändert String:

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

Der eigentliche Typ war jedoch eine Zeichenfolge

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

Durch Entfernen der DateTypeEigenschaft Xmlkann die serialisiert werden

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

Oder

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
quelle