Я успешно использую сериализатор 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-сериализацию?
К сожалению, я также не могу найти никакой документации. Я думаю, вы правы насчет IXmlSerializable. Можете ли вы предложить другой подход к сериализации словаря, включая мое свойство guid? Спасибо
Вы можете повторно реализовать сериализацию с нуля (хотя я уверен, что вы не хотите этого делать!). Или вы можете изменить свою модель данных, чтобы Guid был свойством класса-контейнера, а не самого словаря. Другие обходные пути зависят от того, как SerializableDictionary<,>
реализован IXmlSerializable
. Он сделал это явно? Методы виртуальные?
Я, скорее всего, добавлю guid к объектам значений (например, MyClass) словаря, это то, что вы называете классом контейнера? Я могу проверить информацию о том, как реализован IXmlSerializable, но я думаю, что самый простой способ — добавить свойство к значениям словаря. Вы хотите добавить свой комментарий в качестве ответа? Спасибо
Готовы ли вы сериализовать Guid как атрибут, а не как элемент? Если да, то похоже SerializableDictionary<T1, T2>
Мои знания о терминологии xml довольно ограничены, но Attribute также будет работать, пока я могу прочитать его из десериализованного объекта.
Атрибуты подходят для примитивных значений, таких как строки, целые числа, идентификаторы и т.п. Не подходят для сложных значений с несколькими атрибутами. См. Атрибут XML и элемент XML.
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 является примитивным значением, уместно использование атрибута. Видеть:
Демонстрационная рабочий пример здесь.
Я не могу найти никаких документов для
Microsoft.VisualStudio.Services.Common.SerializableDictionary<T1, T2>
, но посколькуXmlSerializer
не поддерживает словари,SerializableDictionary<T1, T2>
, вероятно, работает, реализуя IXmlSerializable, т. е. сериализует себя вручную, используя код, созданный вручную. Скорее всего, этот код просто не написан для обработки свойств подклассов. Но есть ли у вас ссылка на документ или справочный источник, чтобы перепроверить?