Podczas serializacji C # XML napotkałem kilka problemów, o których myślałem, że się nimi podzielę:
- Nie możesz serializować elementów, które są tylko do odczytu (np. KeyValuePairs)
- Nie możesz serializować słownika ogólnego. Zamiast tego wypróbuj tę klasę opakowania (z 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();
}
}
}
Czy są jakieś inne problemy z serializacją XML?
c#
xml-serialization
dziwne
źródło
źródło
Odpowiedzi:
Kolejna wielka wpadka: podczas wyprowadzania XML przez stronę internetową (ASP.NET) nie chcesz dołączać znaku kolejności bajtów Unicode . Oczywiście sposoby korzystania z zestawienia komponentów są prawie takie same:
BAD (zawiera BOM):
DOBRY:
Możesz jawnie przekazać false, aby wskazać, że nie chcesz BOM. Zwróć uwagę na wyraźną, oczywistą różnicę między
Encoding.UTF8
iUTF8Encoding
.Trzy dodatkowe bajty BOM na początku to (0xEFBBBF) lub (239 187 191).
Źródła: http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/
źródło
XmlTextWriter
w .NET 2.0 lub nowszym.Nie mogę jeszcze komentować, więc skomentuję post Dr8k i poczynię kolejną obserwację. Zmienne prywatne, które są ujawniane jako publiczne właściwości pobierające / ustawiające i są serializowane / deserializowane jako takie za pośrednictwem tych właściwości. Robiliśmy to cały czas w mojej starej pracy.
Należy jednak zauważyć, że jeśli masz jakąkolwiek logikę w tych właściwościach, logika jest uruchamiana, więc czasami kolejność serializacji ma znaczenie. Elementy członkowskie są niejawnie uporządkowane według kolejności w kodzie, ale nie ma żadnych gwarancji, zwłaszcza w przypadku dziedziczenia innego obiektu. Wyraźne zamawianie ich jest utrapieniem.
Zostałem przez to spalony w przeszłości.
źródło
Podczas serializacji do ciągu XML ze strumienia pamięci, pamiętaj, aby użyć MemoryStream # ToArray () zamiast MemoryStream # GetBuffer (), w przeciwnym razie otrzymasz niepotrzebne znaki, które nie będą prawidłowo deserializować (z powodu przydzielonego dodatkowego buforu).
http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer(VS.80).aspx
źródło
Jeśli serializator napotka element członkowski / właściwość, której typem jest interfejs, nie zostanie serializowany. Na przykład następujące elementy nie zostaną serializowane do XML:
Chociaż zostanie to serializowane:
źródło
IEnumerables<T>
które są generowane przez zwroty zysków nie podlegają serializacji. Dzieje się tak, ponieważ kompilator generuje oddzielną klasę w celu zaimplementowania zwrotu zysku i ta klasa nie jest oznaczona jako możliwa do serializacji.źródło
Nie można serializować właściwości tylko do odczytu. Musisz mieć metodę pobierającą i ustawiającą, nawet jeśli nigdy nie zamierzasz używać deserializacji do przekształcania XML w obiekt.
Z tego samego powodu nie można serializować właściwości, które zwracają interfejsy: deserializator nie wiedziałby, jaką konkretną klasę należy utworzyć.
źródło
Och, oto dobry: ponieważ kod serializacji XML jest generowany i umieszczany w oddzielnej bibliotece DLL, nie pojawia się żaden znaczący błąd, gdy w kodzie jest błąd, który powoduje uszkodzenie serializatora. Coś w rodzaju „Nie można zlokalizować s3d3fsdf.dll”. Miły.
źródło
Nie można serializować obiektu, który nie ma konstruktora bez parametrów (właśnie został przez niego ugryziony).
Z jakiegoś powodu z następujących właściwości zostanie serializowana wartość, ale nie FullName:
Nigdy nie udało mi się ustalić, dlaczego, po prostu zmieniłem wartość na wewnętrzną ...
źródło
double?
ale tylkodouble
?null
i dlatego nie będzie generował żadnego XML po serializacjiJeszcze jedna uwaga: nie możesz serializować prywatnych / chronionych członków klas, jeśli używasz „domyślnej” serializacji XML.
Możesz jednak określić niestandardową logikę serializacji XML implementującą IXmlSerializable w Twojej klasie i serializować dowolne pola prywatne, których potrzebujesz / chcesz.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
źródło
Jeśli zestaw wygenerowany przez serializację XML nie znajduje się w tym samym kontekście ładowania, co kod próbujący go użyć, napotkasz niesamowite błędy, takie jak:
Przyczyną tego była dla mnie wtyczka ładowana przy użyciu kontekstu LoadFrom, która ma wiele wad w porównaniu z kontekstem Load. Całkiem niezła zabawa w tropieniu tego.
źródło
Możesz napotkać problemy z serializacją obiektów typu Color i / lub Font.
Oto rady, które mi pomogły:
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
źródło
Szczegółowe informacje o tym, co jest obsługiwane przez serializator XML, a także o sposobie, w jaki obsługiwane są obsługiwane funkcje XSD, można znaleźć w sekcji „Obsługa powiązań atrybutów języka zaawansowanej definicji schematu XML ”.
źródło
Jeśli próbujesz serializować tablicę,
List<T>
lubIEnumerable<T>
zawierający instancji podklasy oT
, trzeba użyć XmlArrayItemAttribute do listy wszystkich używanej podtypy. W przeciwnym razieSystem.InvalidOperationException
podczas serializacji pojawi się niepomocny plik .Oto część pełnego przykładu z dokumentacji
źródło
Prywatne zmienne / właściwości nie są serializowane w domyślnym mechanizmie serializacji XML, ale są w serializacji binarnej.
źródło
Właściwości oznaczone
Obsolete
atrybutem nie są serializowane. Nie testowałemDeprecated
atrybutu, ale zakładam, że zadziałaby w ten sam sposób.źródło
Naprawdę nie mogę tego wyjaśnić, ale stwierdziłem, że to nie będzie serializowane:
ale to będzie:
Warto również zauważyć, że jeśli serializujesz do strumienia memów, możesz chcieć poszukać 0, zanim go użyjesz.
źródło
Uważaj, aby serializować typy bez jawnej serializacji, może to spowodować opóźnienia podczas ich kompilowania .Net. Odkryłem to niedawno podczas serializacji RSAParameters .
źródło
Jeśli XSD korzysta z grup zastępczych, prawdopodobnie nie możesz (de) serializować go automatycznie. Będziesz musiał napisać własne serializatory, aby obsłużyć ten scenariusz.
Na przykład.
W tym przykładzie Koperta może zawierać Wiadomości. Jednak domyślny serializator platformy .NET nie rozróżnia Message, ExampleMessageA i ExampleMessageB. Będzie tylko serializować do iz podstawowej klasy Message.
źródło
Uważam, że jest to również możliwe, jeśli ujawniasz członków prywatnych za pośrednictwem właściwości publicznych - członkowie prywatni nie są serializowani, więc wszyscy członkowie publiczni odwołują się do wartości null.
źródło