How to serialize property of type Object with XmlSerializer

前端 未结 3 2010
我寻月下人不归
我寻月下人不归 2020-12-10 17:10

I have a property:

public object Tag

but it can contain finite number of types, unfortunately without base type (except object type). But w

3条回答
  •  长情又很酷
    2020-12-10 17:55

    I did it implementing the IXmlSerializable interface, writing the object type 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 use no namespace and ASCII encoding, those are non mandatory choices.

    HTH, Cabbi

提交回复
热议问题