XmlSerializer - il y avait une erreur reflétant le type
en utilisant C# .NET 2.0, j'ai une classe de données composite qui a l'attribut [Serializable]
dessus. Je crée une classe XMLSerializer
et je la passe au constructeur:
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
je reçois une exception disant:
il y avait une erreur de type.
dans la classe de données, il y a un autre objet composite. Est-ce que cela doit également avoir le [Serializable]
attribut, ou en l'ayant sur l'objet supérieur, est-ce qu'il l'applique récursivement à tous les objets à l'intérieur?
16 réponses
regardez l'exception intérieure que vous obtenez. Il vous indiquera quel champ / propriété il a des problèmes de sérialisation.
vous pouvez exclure des Champs/propriétés de la sérialisation xml en les décorant avec l'attribut [XmlIgnore]
.
Je ne pense pas que XmlSerializer
utilise l'attribut [Serializable]
, donc je doute que ce soit le problème.
se rappeler que les classes sérialisées doivent avoir des constructeurs par défaut (c.-à-d. sans paramètres). Si vous n'avez pas de constructeur, c'est bien; mais si vous avez un constructeur avec un paramètre, vous devez ajouter la valeur par défaut de trop.
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 (un était une sous-classe de l'autre). L'exception intérieure ressemblait à ceci:
'Types BaseNamespace.Classe1 ' et ' BaseNamespace.SubNamespace.Class1 'les deux utilisent le nom de type XML, 'Class1', de namespace ". Utilisez les attributs XML pour spécifier un nom XML unique et/ou un espace de nom pour le type.
où BaseNamespace.SubNamespace.Classe1 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")]
Note: Si vous avez plus de couches de classes, vous devez y ajouter un attribut.
sachez aussi que XmlSerializer
ne peut pas sérialiser les propriétés abstraites.. Voir ma question ici (à laquelle j'ai ajouté le code de la solution)..
les raisons les Plus communes par moi:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
Tous les objets dans le graphe de sérialisation doivent être sérialisables.
puisque XMLSerializer
est une boîte noire, vérifiez ces liens si vous voulez déboguer plus loin dans le processus de sérialisation..
changement d'emplacement des sorties XmlSerializer assemblages temporaires
comment déboguer dans un assemblage généré par XmlSerializer
si vous avez besoin de gérer des attributs spécifiques (i.e. dictionnaire, ou n'importe quelle classe), vous pouvez mettre en œuvre le ixmlserialable interface, qui vous permettra plus de liberté au coût de plus verbeux codage .
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 intéressant article , qui montrent une façon élégante d'implémenter une façon sophistiquée pour" étendre " le XmlSerializer.
l'article dit:
Ixmlserialisable est couvert dans la documentation officielle, mais la documentation indique qu'il n'est pas destiné à l'usage public et ne fournit aucune information au-delà de cela. 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 pas de raison que ce soit, vous ne pouvez pas en profiter.
parce que ceci, je suggère d'implémenter vos propres classes IXmlSerializable
, afin d'éviter des implémentations trop compliquées.
... il pourrait être simple de mettre en œuvre notre classe personnalisée XmlSerializer
en utilisant la réflexion.
j'ai découvert que la classe de dictionnaire dans .Net 2.0 n'est pas sérialisable en utilisant XML, mais sérialise bien lorsque la sérialisation binaire est utilisée.
j'ai trouvé un travail autour de ici .
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.
moi aussi j'ai pensé que l'attribut Serialisable devait être sur l'objet mais à moins d'être un noob complet (je suis au milieu d'une session de codage tard la nuit) les travaux suivants 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.
j'ai eu une situation où l'Ordre était le même pour les deux éléments dans une rangée
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
.... un peu de code ...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
lorsque j'ai changé le code pour augmenter l'ordre d'un pour chaque nouvelle propriété dans la classe, l'erreur a disparu.
j'ai juste eu la même erreur et j'ai découvert qu'une propriété de type IEnumerable<SomeClass>
était le problème. Il semble que IEnumerable
ne puisse pas être sérialisé directement.
notez également que vous ne pouvez pas sérialiser les contrôles de l'interface utilisateur et que tout objet que vous voulez transmettre sur le presse-papiers doit être sérialisable sinon il ne peut pas être transmis à d'autres processus.
j'ai utilisé la classe NetDataSerialiser
pour sérialiser
mes cours de domaine. NetDataContractSerializer Class .
les classes de domaines sont partagées entre le client et le serveur.
[System.XML.Sérialisation.XmlElementAttribute ("strFieldName", Form = System.XML.Schéma.XmlSchemaForm.Non qualifié)]
//Ou
[XmlIgnore] string [] strFielsName {get; set;}
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.