Я успешно использую сериализатор XML для сериализации Microsoft.VisualStudio.Services.Common.SerializableDictionary<T1, T2>.
Теперь я хочу добавить строку guid в SerializableDictionary и также сериализовать ее. Поэтому я создал следующий класс:
public class SerializableDictWithGuid<T1, T2> : SerializableDictionary<T1, T2>, IMyInterface
{
[XmlElement(ElementName = idXml001)]
public string Guid { get; set; } = string.Empty;
}
При сериализации SerializableDictWithGuid с помощью приведенного ниже кода строка GUID отсутствует в выходных данных XML.
public class XmlSerializeHelper<T> where T : class
{
public static string Serialize(T obj)
{
try
{
System.Xml.Serialization.XmlSerializer xsSubmit = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (var sww = new StringWriter())
{
using (XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented })
{
xsSubmit.Serialize(writer, obj);
}
return sww.ToString();
}
}
catch (Exception ex)
{
logger.log(ex);
}
return string.Empty;
}
}
Минимальный воспроизводимый пример
SerializableDictWithGuid <string, string> test = new SerializableDictWithGuid <string, string>() { Guid = "123" };
XmlSerializeHelper<SerializableDictWithGuid <string, string>>.Serialize(test);
Вопрос: как добавить свойства в SerializableDictionary и включить их в XML-сериализацию?
🤔 А знаете ли вы, что...
C# поддерживает множество парадигм программирования, включая процедурное, объектно-ориентированное и функциональное программирование.
XmlSerializer
не поддерживает словари , поэтому SerializableDictionary<T1, T2>
работает за счет реализации IXmlSerializable. То есть он сериализует себя вручную, используя написанный вручную код. Таким образом, этот код ничего не знает о свойствах подклассов и не имеет никакого кода для их автоматического обнаружения и сериализации.
К счастью, оказывается, что IXmlSerializable.ReadXml()
и IXmlSerializable.WriteXml()
не были реализованы явно, поэтому должна быть возможность повторно реализовать их через повторную реализацию интерфейса и по-прежнему вызывать методы базового класса. И хотя в целом сложно реализовать IXmlSerializable
, если вы сделаете Guid
атрибутом XML, а не элементом, реализация станет простой, потому что, хотя дизайн IXmlSerializable
не позволяет производным классам внедрять дочерние элементы, он позволяет производным классам вводить пользовательские атрибуты:
public class SerializableDictWithGuid<T1, T2> : SerializableDictionary<T1, T2>, IMyInterface, IXmlSerializable // Re-implement IXmlSerializable
{
const string idXml001 = "idXml001";
public string Guid { get; set; } = string.Empty;
public new void ReadXml(XmlReader reader)
{
reader.MoveToContent();
// At this point the reader is positioned on the beginning of the container element for the dictionary, so we can get any custom attributes we wrote.
Guid = reader.GetAttribute(idXml001);
base.ReadXml(reader);
}
public new void WriteXml(XmlWriter writer)
{
// At this point the container element has been written but nothing else, so it's still possible to add some attributes.
if (Guid != null)
writer.WriteAttributeString(idXml001, Guid);
base.WriteXml(writer);
}
}
В результате получается XML, который выглядит так:
<SerializableDictWithGuidOfStringString idXml001 = "123">
<item>
<key>
<string>hello</string>
</key>
<value>
<string>there</string>
</value>
</item>
</SerializableDictWithGuidOfStringString>
Стандарт XML гласит, что
Атрибуты используются для связывания пар имя-значение с элементами.
В целом атрибуты подходят для фиксированных наборов простых, примитивных значений, таких как имена и идентификаторы. Сложные значения с несколькими внутренними свойствами или повторяющиеся значения (например, коллекции) должны быть дочерними элементами, а не атрибутами. Поскольку идентифицирующий Guid является примитивным значением, уместно использование атрибута. Видеть:
Демонстрационная рабочий пример здесь.