Bei der C # XML-Serialisierung sind mir einige Fallstricke begegnet, von denen ich dachte, ich würde sie teilen:
- Sie können keine schreibgeschützten Elemente (wie KeyValuePairs) serialisieren.
- Sie können ein generisches Wörterbuch nicht serialisieren. Versuchen Sie stattdessen diese Wrapper-Klasse (von 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();
}
}
}
Gibt es noch andere Fallstricke bei der XML-Serialisierung?
c#
xml-serialization
kurious
quelle
quelle
Antworten:
Ein weiteres großes Problem: Wenn Sie XML über eine Webseite (ASP.NET) ausgeben, möchten Sie das Unicode-Byte-Order-Zeichen nicht einfügen . Natürlich sind die Möglichkeiten, die Stückliste zu verwenden oder nicht zu verwenden, fast gleich:
BAD (einschließlich Stückliste):
GUT:
Sie können explizit false übergeben, um anzugeben, dass Sie die Stückliste nicht möchten. Beachten Sie den klaren, offensichtlichen Unterschied zwischen
Encoding.UTF8
undUTF8Encoding
.Die drei zusätzlichen Stücklistenbytes am Anfang sind (0xEFBBBF) oder (239 187 191).
Referenz: http://chrislaco.com/blog/troubleshooter-common-problems-with-the-xmlserializer/
quelle
XmlTextWriter
in .NET 2.0 oder höher verwenden.Ich kann noch keine Kommentare abgeben, daher werde ich den Beitrag von Dr8k kommentieren und eine weitere Bemerkung machen. Private Variablen, die als öffentliche Getter- / Setter-Eigenschaften verfügbar gemacht werden und über diese Eigenschaften als solche serialisiert / deserialisiert werden. Wir haben es die ganze Zeit bei meinem alten Job gemacht.
Eine Sache zu beachten ist jedoch, dass, wenn Sie eine Logik in diesen Eigenschaften haben, die Logik ausgeführt wird, so dass manchmal die Reihenfolge der Serialisierung tatsächlich wichtig ist. Die Mitglieder sind implizit nach der Reihenfolge im Code geordnet, es gibt jedoch keine Garantien, insbesondere wenn Sie ein anderes Objekt erben. Sie explizit zu bestellen ist ein Schmerz im Heck.
Das hat mich in der Vergangenheit verbrannt.
quelle
Stellen Sie beim Serialisieren in eine XML-Zeichenfolge aus einem Speicherstrom sicher, dass Sie MemoryStream # ToArray () anstelle von MemoryStream # GetBuffer () verwenden. Andernfalls werden Junk-Zeichen angezeigt, die nicht ordnungsgemäß deserialisiert werden (aufgrund des zugewiesenen zusätzlichen Puffers).
http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer(VS.80).aspx
quelle
Wenn der Serializer auf ein Mitglied / eine Eigenschaft stößt, deren Typ eine Schnittstelle hat, wird er nicht serialisiert. Beispielsweise wird Folgendes nicht in XML serialisiert:
Dies wird jedoch serialisiert:
quelle
IEnumerables<T>
die über Renditerenditen generiert werden, sind nicht serialisierbar. Dies liegt daran, dass der Compiler eine separate Klasse generiert, um die Ertragsrückgabe zu implementieren, und diese Klasse nicht als serialisierbar markiert ist.quelle
Sie können schreibgeschützte Eigenschaften nicht serialisieren. Sie müssen einen Getter und einen Setter haben, auch wenn Sie niemals die Deserialisierung verwenden möchten, um XML in ein Objekt umzuwandeln.
Aus dem gleichen Grund können Sie keine Eigenschaften serialisieren, die Schnittstellen zurückgeben: Der Deserializer weiß nicht, welche konkrete Klasse instanziiert werden soll.
quelle
Oh, hier ist eine gute: Da der XML-Serialisierungscode generiert und in einer separaten DLL abgelegt wird, erhalten Sie keinen aussagekräftigen Fehler, wenn in Ihrem Code ein Fehler vorliegt, der den Serializer beschädigt. Nur so etwas wie "s3d3fsdf.dll kann nicht gefunden werden". Nett.
quelle
Ein Objekt, das keinen parameterlosen Construtor hat, kann nicht serialisiert werden (wurde gerade von diesem gebissen).
Aus irgendeinem Grund wird Value aus den folgenden Eigenschaften serialisiert, nicht jedoch FullName:
Ich habe nie herausgefunden, warum, ich habe nur Value in intern geändert ...
quelle
double?
aber nurdouble
?null
und wird daher kein XML generieren, wenn es serialisiert wirdNoch etwas zu beachten: Sie können keine privaten / geschützten Klassenmitglieder serialisieren, wenn Sie die "Standard" XML-Serialisierung verwenden.
Sie können jedoch eine benutzerdefinierte XML-Serialisierungslogik angeben, die IXmlSerializable in Ihrer Klasse implementiert, und alle privaten Felder, die Sie benötigen / möchten, serialisieren.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
quelle
Wenn sich Ihre von der XML-Serialisierung generierte Assembly nicht im selben Ladekontext befindet wie der Code, der versucht, sie zu verwenden, treten tolle Fehler auf:
Die Ursache dafür war für mich ein Plugin, das im LoadFrom-Kontext geladen wurde und viele Nachteile bei der Verwendung des Load-Kontexts hat. Ziemlich viel Spaß beim Aufspüren.
quelle
Möglicherweise treten Probleme beim Serialisieren von Objekten vom Typ Farbe und / oder Schriftart auf.
Hier sind die Ratschläge, die mir geholfen haben:
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
quelle
Weitere Informationen zur Unterstützung durch den XML Serializer und zur Unterstützung der unterstützten XSD-Funktionen finden Sie unter " Unterstützung für die Bindung von Attributen für erweiterte XML-Schemadefinitionen ".
quelle
Wenn Sie versuchen, ein Array zu serialisieren
List<T>
, oderIEnumerable<T>
das Instanzen von Unterklassen von enthältT
, müssen Sie das XmlArrayItemAttribute verwenden, um alle verwendeten Untertypen aufzulisten . Andernfalls erhalten SieSystem.InvalidOperationException
zur Laufzeit beim Serialisieren eine nicht hilfreiche Datei.Hier ist ein Teil eines vollständigen Beispiels aus der Dokumentation
quelle
Private Variablen / Eigenschaften werden im Standardmechanismus für die XML-Serialisierung nicht serialisiert, sondern in der binären Serialisierung.
quelle
Mit dem
Obsolete
Attribut gekennzeichnete Eigenschaften werden nicht serialisiert. Ich habe nicht mitDeprecated
Attribut getestet , aber ich gehe davon aus, dass es genauso funktionieren würde.quelle
Ich kann das nicht wirklich erklären, aber ich habe festgestellt, dass es nicht serialisiert wird:
aber das wird:
Beachten Sie auch, dass Sie bei der Serialisierung eines Memstreams möglicherweise vor der Verwendung auf 0 suchen möchten, bevor Sie ihn verwenden.
quelle
Seien Sie vorsichtig bei der Serialisierung von Typen ohne explizite Serialisierung. Dies kann zu Verzögerungen führen, während .Net sie erstellt. Ich habe dies kürzlich bei der Serialisierung von RSAP-Parametern entdeckt .
quelle
Wenn Ihre XSD Substitutionsgruppen verwendet, können Sie sie wahrscheinlich nicht automatisch (de) serialisieren. Sie müssen Ihre eigenen Serializer schreiben, um dieses Szenario zu handhaben.
Z.B.
In diesem Beispiel kann ein Umschlag Nachrichten enthalten. Der Standard-Serializer von .NET unterscheidet jedoch nicht zwischen Message, ExampleMessageA und ExampleMessageB. Es wird nur zur und von der Basisnachrichtenklasse serialisiert.
quelle
Ich glaube, das bringt Sie auch, wenn Sie die privaten Mitglieder über öffentliche Eigenschaften verfügbar machen - die privaten Mitglieder werden nicht serialisiert, sodass alle öffentlichen Mitglieder auf Nullwerte verweisen.
quelle