XmlSerializer - Une erreur s'est produite lors de la réflexion du type

332

En utilisant C # .NET 2.0, j'ai une classe de données composite qui a l' [Serializable]attribut dessus. Je crée une XMLSerializerclasse et la transmets au constructeur:

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

Je reçois une exception disant:

Une erreur s'est produite lors de la réflexion du type.

À l'intérieur de la classe de données, il y a un autre objet composite. Doit-il également avoir l' [Serializable]attribut, ou en le plaçant sur l'objet supérieur, l'applique-t-il récursivement à tous les objets à l'intérieur?

leora
la source

Réponses:

413

Regardez l'exception intérieure que vous obtenez. Il vous indiquera quel champ / propriété il a du mal à sérialiser.

Vous pouvez exclure des champs / propriétés de la sérialisation XML en les décorant avec l' [XmlIgnore]attribut.

XmlSerializern'utilise pas l' [Serializable]attribut, donc je doute que ce soit le problème.

Lamar
la source
11
Mon objet avait un champ Uri, ce qui a provoqué cette exception; la classe Uri n'a pas de constructeur sans paramètre. Merci pour le conseil.
ford
10
Je suis tombé sur cela avec une recherche Google - mon problème particulier était d'avoir une propriété dans ma classe "à sérialiser" comme IListquand elle devait l'être List.
Paul Aldred-Bann
7
Comment regarde-t-on une "exception intérieure"?
David
7
ou ajoutez '@exception' à une montre
arolson101
19
Merci, cette réponse m'a aidé. J'ai d'abord regardé l'exception intérieure, et j'ai juste vu mentionner la classe principale. Mais je me suis rendu compte que je pouvais explorer les innerexceptions des innrexceptions, et finalement, 5 niveaux plus bas, j'ai trouvé le problème. J'avais des cours qui étaient contradictoires. Merci.
Louis van Tonder
111

N'oubliez pas que les classes sérialisées doivent avoir des constructeurs par défaut (c'est-à-dire sans paramètre). Si vous n'avez pas de constructeur du tout, c'est bien; mais si vous avez un constructeur avec un paramètre, vous devrez également ajouter celui par défaut.

Jeremy McGee
la source
4
Merci pour le rappel! Je déteste qu'il s'agit d'une erreur d'exécution avec peu d'explications.
Jared Updike
Je continue de faire cette erreur encore et encore. merci de me rappeler d'utiliser un constructeur sans paramètre ^^
aZtraL-EnForceR
25

J'ai eu un problème similaire, et il s'est avéré que le sérialiseur ne pouvait pas distinguer entre 2 classes que j'avais avec le même nom (l'une était une sous-classe de l'autre). L'exception intérieure ressemblait à ceci:

'Types BaseNamespace.Class1' et 'BaseNamespace.SubNamespace.Class1' utilisent tous deux le nom de type XML, 'Class1', à partir de l'espace de noms ''. Utilisez des attributs XML pour spécifier un nom XML unique et / ou un espace de noms pour le type.

Où BaseNamespace.SubNamespace.Class1 est une sous-classe de BaseNamespace.Class1.

Ce que je devais faire était d'ajouter un attribut à l'une des classes (j'ai ajouté à la classe de base):

[XmlType("BaseNamespace.Class1")]

Remarque: Si vous avez plusieurs couches de classes, vous devez également leur ajouter un attribut.

Dennis Calla
la source
Cela a résolu le problème pour moi, merci, +1; J'avais un paramètre similaire avec plusieurs objets Processor *, chacun avec une classe interne Config. Le runtime n'a pas pu faire la distinction entre SomeNS.Processor1.Config et SomeNS.Processor2.Config.
damix911
7

Sachez également que XmlSerializervous ne pouvez pas sérialiser les propriétés abstraites .. Voir ma question ici (à laquelle j'ai ajouté le code de la solution) ..

Sérialisation XML et types hérités

Rob Cooper
la source
6

Les raisons les plus courantes de moi:

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

Si vous devez gérer des attributs spécifiques (c.-à-d. Dictionnaire ou n'importe quelle classe), vous pouvez implémenter l' interface IXmlSerialiable , qui vous donnera plus de liberté au prix d'un codage plus détaillé .

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
}

Il y a un article intéressant , qui montre une manière élégante d'implémenter une manière sophistiquée "d'étendre" le XmlSerializer.


L'article dit:

IXmlSerializable est couvert dans la documentation officielle, mais la documentation indique qu'elle n'est pas destinée à un usage public et ne fournit aucune information au-delà. Cela indique que l'équipe de développement a voulu se réserver le droit de modifier, désactiver ou même supprimer complètement ce crochet d'extensibilité sur la route. Cependant, tant que vous êtes prêt à accepter cette incertitude et à faire face à d'éventuels changements à l'avenir, il n'y a aucune raison que vous ne puissiez pas en profiter.

Parce que cela, je suggère d'implémenter vos propres IXmlSerializableclasses, afin d'éviter des implémentations trop compliquées.

... il pourrait être simple d'implémenter notre XmlSerializerclasse personnalisée en utilisant la réflexion.

Luca
la source
4

J'ai découvert que la classe Dictionary dans .Net 2.0 n'est pas sérialisable à l'aide de XML, mais sérialise bien lorsque la sérialisation binaire est utilisée.

J'ai trouvé un travail par ici .

Charlie Salts
la source
3

J'ai récemment obtenu ceci dans une classe partielle de référence Web lors de l'ajout d'une nouvelle propriété. La classe générée automatiquement ajoutait les attributs suivants.

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

J'avais besoin d'ajouter un attribut similaire avec un ordre supérieur au dernier dans la séquence générée automatiquement et cela l'a corrigé pour moi.

LepardUK
la source
3

Je viens de recevoir la même erreur et j'ai découvert qu'une propriété de type IEnumerable<SomeClass>était le problème. Il semble que IEnumerablecela ne peut pas être sérialisé directement.

Au lieu de cela, on pourrait utiliser List<SomeClass>.

jkokorian
la source
2

Moi aussi, je pensais que l'attribut Serializable devait être sur l'objet, mais à moins que je ne sois un noob complet (je suis au milieu d'une session de codage tard dans la nuit), les œuvres suivantes du 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();
        }
    }

}

J'imagine que le XmlSerializer utilise la réflexion sur les propriétés publiques.

Darren
la source
1

J'ai eu une situation où l'Ordre était le même pour deux éléments d'affilée

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

.... du code ...

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

Lorsque j'ai changé le code pour incrémenter l'ordre de un pour chaque nouvelle propriété de la classe, l'erreur a disparu.

Jeremy Brown
la source
1

J'obtenais la même erreur lorsque j'ai créé une propriété ayant un type de données - Type. Sur ce, je recevais une erreur - Il y avait une erreur reflétant le type. J'ai continué à vérifier l '«InnerException» de chaque exception du débogage et j'ai obtenu le nom de champ spécifique (qui était Type) dans mon cas. La solution est la suivante:

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

Notez également que vous ne pouvez pas sérialiser les contrôles de l'interface utilisateur et que tout objet que vous souhaitez passer dans le presse-papiers doit être sérialisable sinon il ne peut pas être transmis à d'autres processus.

Phil Wright
la source
0

J'utilise la NetDataSerialiserclasse pour sérialiser mes classes de domaine. Classe NetDataContractSerializer .

Les classes de domaine sont partagées entre le client et le serveur.

Peter Mortensen
la source
0

J'ai eu le même problème et dans mon cas, l'objet avait une ReadOnlyCollection. Une collection doit implémenter la méthode Add pour être sérialisable.

Curious Dev
la source
Ce n'est pas une bonne réponse à la question. Il y a déjà 15 autres réponses sur cette question. Si vous pensez que votre réponse est meilleure que les autres, vous devez fournir plus de détails à ce sujet. Fournir des extraits de code et de sortie aide toujours les utilisateurs. Avant de publier vos réponses, pensez à lire -> stackoverflow.com/help/how-to-answer
Amit Phaltankar
0

J'ai une solution légèrement différente à toutes celles décrites ici jusqu'à présent, donc pour toute civilisation future, voici la mienne!

J'avais déclaré un type de données de "temps" car le type d'origine était un TimeSpanet changé par la suite en un String:

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

mais le type réel était une chaîne

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

en supprimant la DateTypepropriété, le Xmlpeut être sérialisé

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

Ou

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