J'ai rencontré quelques pièges lors de la sérialisation XML C # que je pensais partager:
- Vous ne pouvez pas sérialiser des éléments en lecture seule (comme KeyValuePairs)
- Vous ne pouvez pas sérialiser un dictionnaire générique. À la place, essayez cette classe de wrapper (à partir de http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx ):
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
Y a-t-il d'autres pièges de sérialisation XML?
c#
xml-serialization
kurious
la source
la source
Réponses:
Un autre énorme problème: lors de la sortie de XML via une page Web (ASP.NET), vous ne voulez pas inclure la marque d'ordre d'octet Unicode . Bien entendu, les façons d'utiliser ou non la nomenclature sont presque les mêmes:
MAUVAIS (comprend la nomenclature):
BIEN:
Vous pouvez explicitement passer false pour indiquer que vous ne voulez pas la nomenclature. Notez la différence claire et évidente entre
Encoding.UTF8
etUTF8Encoding
.Les trois octets de nomenclature supplémentaires au début sont (0xEFBBBF) ou (239 187 191).
Référence: http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/
la source
XmlTextWriter
dans .NET 2.0 ou supérieur.Je ne peux pas encore faire de commentaires, donc je vais commenter le post de Dr8k et faire une autre observation. Les variables privées qui sont exposées en tant que propriétés publiques getter / setter, et qui sont sérialisées / désérialisées en tant que telles via ces propriétés. Nous l'avons fait à mon ancien travail à l'époque.
Une chose à noter cependant est que si vous avez une logique dans ces propriétés, la logique est exécutée, donc parfois, l'ordre de sérialisation compte réellement. Les membres sont implicitement classés en fonction de leur ordre dans le code, mais il n'y a aucune garantie, en particulier lorsque vous héritez d'un autre objet. Les commander explicitement est une douleur à l'arrière.
J'ai été brûlé par ça dans le passé.
la source
Lors de la sérialisation dans une chaîne XML à partir d'un flux mémoire, veillez à utiliser MemoryStream # ToArray () au lieu de MemoryStream # GetBuffer () ou vous vous retrouverez avec des caractères indésirables qui ne seront pas désérialisés correctement (à cause du tampon supplémentaire alloué).
http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer(VS.80).aspx
la source
Si le sérialiseur rencontre un membre / une propriété dont le type est une interface, il ne sérialisera pas. Par exemple, les éléments suivants ne seront pas sérialisés en XML:
Bien que cela sérialisera:
la source
IEnumerables<T>
qui sont générés via les rendements de rendement ne sont pas sérialisables. Cela est dû au fait que le compilateur génère une classe distincte pour implémenter le rendement et que cette classe n'est pas marquée comme sérialisable.la source
Vous ne pouvez pas sérialiser les propriétés en lecture seule. Vous devez avoir un getter et un setter, même si vous n'avez jamais l'intention d'utiliser la désérialisation pour transformer XML en objet.
Pour la même raison, vous ne pouvez pas sérialiser les propriétés qui renvoient des interfaces: le désérialiseur ne saurait pas quelle classe concrète instancier.
la source
Oh, en voici une bonne: puisque le code de sérialisation XML est généré et placé dans une DLL distincte, vous n'obtenez aucune erreur significative lorsqu'il y a une erreur dans votre code qui brise le sérialiseur. Juste quelque chose comme "impossible de localiser s3d3fsdf.dll". Agréable.
la source
Impossible de sérialiser un objet qui n'a pas de constructeur sans paramètre (juste mordu par celui-là).
Et pour une raison quelconque, à partir des propriétés suivantes, Value est sérialisé, mais pas FullName:
Je n'ai jamais compris pourquoi, j'ai juste changé la valeur en interne ...
la source
double?
mais justedouble
?null
et ne générera donc pas de XML une fois sérialiséUne dernière chose à noter: vous ne pouvez pas sérialiser les membres de classe privés / protégés si vous utilisez la sérialisation XML "par défaut".
Mais vous pouvez spécifier une logique de sérialisation XML personnalisée implémentant IXmlSerializable dans votre classe et sérialiser tous les champs privés dont vous avez besoin / souhaitez.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
la source
Si votre assembly généré par sérialisation XML n'est pas dans le même contexte de chargement que le code qui tente de l'utiliser, vous rencontrerez des erreurs impressionnantes telles que:
La cause de cela pour moi était un plugin chargé à l'aide du contexte LoadFrom qui présente de nombreux inconvénients par rapport à l'utilisation du contexte Load. C'est un peu amusant de suivre celui-là.
la source
Vous pouvez rencontrer des problèmes de sérialisation d'objets de type Couleur et / ou Police.
Voici les conseils qui m'ont aidé:
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
la source
Voir « Prise en charge de la liaison d'attributs de langage de définition de schéma XML avancé » pour plus de détails sur ce qui est pris en charge par le sérialiseur XML et pour des détails sur la manière dont les fonctionnalités XSD prises en charge sont prises en charge.
la source
Si vous essayez de sérialiser un tableau,
List<T>
ouIEnumerable<T>
qui contient des instances de sous - classes deT
, vous devez utiliser XmlArrayItemAttribute pour répertorier tous les sous-types utilisés. Sinon, vous obtiendrez un message inutileSystem.InvalidOperationException
lors de l'exécution lors de la sérialisation.Voici une partie d'un exemple complet de la documentation
la source
Les variables / propriétés privées ne sont pas sérialisées dans le mécanisme par défaut pour la sérialisation XML, mais sont dans la sérialisation binaire.
la source
Les propriétés marquées avec l'
Obsolete
attribut ne sont pas sérialisées. Je n'ai pas testé avec l'Deprecated
attribut mais je suppose que cela agirait de la même manière.la source
Je ne peux pas vraiment expliquer celui-ci, mais j'ai trouvé que cela ne sérialisera pas:
mais cela va:
Et il convient également de noter que si vous sérialisez vers un memstream, vous voudrez peut-être rechercher 0 avant de l'utiliser.
la source
Soyez prudent en sérialisant les types sans sérialisation explicite, cela peut entraîner des retards pendant que .Net les construit. J'ai découvert cela récemment en sérialisant les paramètres RSAP .
la source
Si votre XSD utilise des groupes de substitution, il est probable que vous ne puissiez pas (dé) sérialiser automatiquement. Vous devrez écrire vos propres sérialiseurs pour gérer ce scénario.
Par exemple.
Dans cet exemple, une enveloppe peut contenir des messages. Cependant, le sérialiseur par défaut du .NET ne fait pas la distinction entre Message, ExampleMessageA et ExampleMessageB. Il ne sérialisera que vers et depuis la classe Message de base.
la source
Je pense que cela vous permet également si vous exposez les membres privés via des propriétés publiques - les membres privés ne sont pas sérialisés, de sorte que les membres publics font tous référence à des valeurs nulles.
la source