How to serialize a property of type Object using XmlSerializer

I have a property:

public object Tag 

but it can contain a finite number of types, unfortunately, without a base type (except for the type of an object). But when I serialize an object with this property, it does not become serialized. Is there a way to instruct XmlSerializer with possible types?

+6
source share
3 answers

I do not recommend this, but yes, you can use [XmlElement] etc. to talk about several types of candidates for a member:

 public class Test { private static void Main() { var ser = new XmlSerializer(typeof (Test)); var obj = new Test {Value = "abc"}; ser.Serialize(Console.Out, obj); obj = new Test { Value = 123 }; ser.Serialize(Console.Out, obj); obj = new Test { Value = 456.7F }; ser.Serialize(Console.Out, obj); } [XmlElement("a", Type = typeof(int))] [XmlElement("b", Type = typeof(string))] [XmlElement("c", Type = typeof(float))] public object Value { get; set; } } 

Important output bits (ignoring all xmlns / <?xml> etc.):

 <Test> <b>abc</b> </Test> <Test> <a>123</a> </Test> <Test> <c>456.7</c> </Test> 
+10
source

I did this by implementing the interface of IXmlSerializable , recording the type of the object as an element attribute.

  public void ReadXml(XmlReader reader) { reader.MoveToContent(); Boolean isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { // ...here comes all other properties deserialization object tag; if (ReadXmlObjectProperty(reader, "Tag", out tag)) { Tag = tag; } reader.ReadEndElement(); } } public void WriteXml(XmlWriter writer) { // ...here comes all other properties serialization WriteXmlObjectProperty(writer, "Tag", Tag); } public static bool ReadXmlObjectProperty(XmlReader reader, string name, out object value) { value = null; // Moves to the element while (!reader.IsStartElement(name)) { return false; } // Get the serialized type string typeName = reader.GetAttribute("Type"); Boolean isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { Type type = Type.GetType(typeName); if (type != null) { // Deserialize it XmlSerializer serializer = new XmlSerializer(type); value = serializer.Deserialize(reader); } else { // Type not found within this namespace: get the raw string! string xmlTypeName = typeName.Substring(typeName.LastIndexOf('.')+1); value = reader.ReadElementString(xmlTypeName); } reader.ReadEndElement(); } return true; } public static void WriteXmlObjectProperty(XmlWriter writer, string name, object value) { if (value != null) { Type valueType = value.GetType(); writer.WriteStartElement(name); writer.WriteAttributeString("Type", valueType.FullName); writer.WriteRaw(ToXmlString(value, valueType)); writer.WriteFullEndElement(); } } public static string ToXmlString(object item, Type type) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.ASCII; settings.Indent = true; settings.OmitXmlDeclaration = true; settings.NamespaceHandling = NamespaceHandling.OmitDuplicates; using(StringWriter textWriter = new StringWriter()) using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { XmlSerializer serializer = new XmlSerializer(type); serializer.Serialize(xmlWriter, item, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); return textWriter.ToString(); } } 

Note: in the code I do not use namespace and ASCII encoding, these are optional options.

NTN, Cabbi

0
source

You can also use [XmlInclude(typeof(YourType))] in the class that contains the property of the object. Therefore, in the case of OP, it will look like

 [XmlInclude(typeof(PossibleClassOne))] [XmlInclude(typeof(PossibleClassTwo))] public class MyClass { public object Tag { get; set; } } 

This way you can save the name of the <Tag> element in all cases

0
source

Source: https://habr.com/ru/post/909618/


All Articles