При сериализации C # XML я столкнулся с несколькими подводными камнями, которыми, как я думал, поделюсь:
- Вы не можете сериализовать элементы, доступные только для чтения (например, KeyValuePairs)
- Вы не можете сериализовать общий словарь. Вместо этого попробуйте этот класс-оболочку (из 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();
}
}
}
Есть ли другие проблемы с сериализацией XML?
c#
xml-serialization
kurious
источник
источник
Ответы:
Еще одна большая проблема: при выводе XML через веб-страницу (ASP.NET) вы не хотите включать метку байтового порядка Unicode . Конечно, способы использования или отказа от спецификации почти одинаковы:
ПЛОХО (включая спецификацию):
ХОРОШО:
Вы можете явно передать false, чтобы указать, что вам не нужна спецификация. Обратите внимание на четкую, очевидную разницу между
Encoding.UTF8
иUTF8Encoding
.Три дополнительных байта спецификации в начале: (0xEFBBBF) или (239 187 191).
Ссылка: http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/
источник
XmlTextWriter
.NET 2.0 или выше.Я пока не могу комментировать, поэтому прокомментирую сообщение Dr8k и сделаю еще одно наблюдение. Частные переменные, которые представлены как общедоступные свойства получателя / установщика и сериализованы / десериализованы как таковые через эти свойства. Мы всегда так делали на моей старой работе.
Однако следует отметить, что если у вас есть какая-либо логика в этих свойствах, она запускается, поэтому иногда порядок сериализации действительно имеет значение. Члены неявно упорядочены по тому, как они упорядочены в коде, но нет никаких гарантий, особенно когда вы наследуете другой объект. Явный заказ их - заноза в задней части.
Я был обожжен этим в прошлом.
источник
При сериализации в XML-строку из потока памяти обязательно используйте MemoryStream # ToArray () вместо MemoryStream # GetBuffer (), иначе вы получите ненужные символы, которые не будут десериализоваться должным образом (из-за выделенного дополнительного буфера).
http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer(VS.80).aspx
источник
Если сериализатор встречает член / свойство, тип которого имеет интерфейс, он не будет сериализован. Например, следующее не будет сериализовано в XML:
Хотя это будет сериализовано:
источник
IEnumerables<T>
которые генерируются с помощью возвратов yield, не сериализуемы. Это связано с тем, что компилятор создает отдельный класс для реализации yield return, и этот класс не помечен как сериализуемый.источник
Вы не можете сериализовать свойства, доступные только для чтения. У вас должны быть геттер и сеттер, даже если вы никогда не собираетесь использовать десериализацию для превращения XML в объект.
По той же причине вы не можете сериализовать свойства, которые возвращают интерфейсы: десериализатор не будет знать, какой конкретный класс создать.
источник
О, вот хороший пример: поскольку код сериализации XML генерируется и помещается в отдельную DLL, вы не получите никаких значимых ошибок, если в вашем коде есть ошибка, которая нарушает работу сериализатора. Просто что-то вроде «не удалось найти s3d3fsdf.dll». Ницца.
источник
Невозможно сериализовать объект, у которого нет конструктора без параметров (только что его укусил).
И по какой-то причине из следующих свойств сериализуется Value, но не FullName:
Я так и не понял почему, я просто изменил Value на внутреннее ...
источник
double?
а простоdouble
?null
будет генерировать XML при сериализацииЕще одно замечание: вы не можете сериализовать частные / защищенные члены класса, если вы используете сериализацию XML "по умолчанию".
Но вы можете указать пользовательскую логику сериализации XML, реализующую IXmlSerializable в своем классе, и сериализовать любые частные поля, которые вам нужны / нужны.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
источник
Если ваша сгенерированная сборка XML-сериализации не находится в том же контексте загрузки, что и код, пытающийся ее использовать, вы столкнетесь с ужасными ошибками, например:
Причиной этого для меня был плагин, загруженный с использованием контекста LoadFrom, который имеет много недостатков в использовании контекста Load. Довольно забавно отслеживать это.
источник
Вы можете столкнуться с проблемами сериализации объектов типа Color и / или Font.
Вот советы, которые мне помогли:
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
источник
См. « Поддержка привязки атрибутов расширенного языка определения схемы XML » для получения подробной информации о том, что поддерживается XML-сериализатором, а также для получения подробной информации о том, как поддерживаются поддерживаемые функции XSD.
источник
Если вы попытаетесь сериализовать массив,
List<T>
илиIEnumerable<T>
который содержит экземпляры подклассов изT
, вы должны использовать XmlArrayItemAttribute к списку всех подтипов используются. В противном случае вы получите бесполезный сигналSystem.InvalidOperationException
во время выполнения при сериализации.Вот часть полного примера из документации
источник
Частные переменные / свойства не сериализуются в механизме по умолчанию для сериализации XML, но находятся в двоичной сериализации.
источник
Свойства, отмеченные
Obsolete
атрибутом, не сериализуются. Я не тестировал сDeprecated
атрибутом, но предполагаю, что он будет действовать так же.источник
Я не могу объяснить это, но я обнаружил, что это не сериализуется:
но это будет:
Также стоит отметить, что если вы сериализуете поток памяти, вы можете захотеть найти 0, прежде чем использовать его.
источник
Будьте осторожны при сериализации типов без явной сериализации, это может привести к задержкам при их построении .Net. Я обнаружил это недавно при сериализации RSAParameters .
источник
Если ваш XSD использует группы подстановки, то, скорее всего, вы не можете (де) сериализовать его автоматически. Вам нужно будет написать свои собственные сериализаторы для обработки этого сценария.
Например.
В этом примере конверт может содержать сообщения. Однако сериализатор .NET по умолчанию не делает различий между Message, ExampleMessageA и ExampleMessageB. Он будет сериализоваться только в базовый класс Message и обратно.
источник
Я считаю, что это также поможет вам, если вы раскрываете частные члены через общедоступные свойства - частные члены не сериализуются, поэтому все общедоступные члены ссылаются на нулевые значения.
источник