简体   繁体   中英

Unable to serialize a derived class to XML

I am trying to serialize following class hierarchy:

public class Control
    {
        public virtual string Name {get; set;}

        public virtual string Type {get; set;}

        public virtual string Text { get; set; }

        public virtual SerializableFont Font { get; set; }

        private Operation op = new Operation();
        public Operation Events { get { return op; } }
    }
[System.Xml.Serialization.XmlInclude(typeof(Control))]
    public class TextProperties : Control
    {
        public Label txt;

        public TextProperties()
        {
        }

        public override string Type
        {
            get { return "Text"; }
        }
        public override string Text
        {
            get { return txt.Text; }
            set
            {
                txt.Text = value;
            }
        }
        public override SerializableFont Font
        {
            get { return new SerializableFont(txt.Font); }
            set
            {
                txt.Font = new SerializableFont().Font ;
            }
        }
    }

As you can see I am including the base class but still its throwing following exception:

The type TextProperties was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

I´m not sure that the problem is really your class hierarchy itself, it seems to be okay. You dont need to add the attribute.

Instead, you are likely trying to read/write an object of type TextProperties with an XmlSerializer created for objects of type Control. That won´t work, you need to use the serializer created specific to the type to serialize / deserialize.

If this is not known at compile time, try to create a wrapping class that implements IXMLSerializable. When reading, this class must first read data to define the class of the wrapped object (a node attribute named "TypeName", for example). It must then create the specific serializer for the given type at runtime and use it to load the wrapped object.

EDIT: Here is some sample code how it could be done. You will need to implement GetTypeByName yourself (eg. crawling through all loaded assemblies or just "hardwiring" some strings to a specific type you expect). The code should suffice to be integrated into a class with a property "WrappedObject".

  public XmlSchema GetSchema()
  {
     return null;
  }

  public void ReadXml(XmlReader reader)
  {
     reader.MoveToContent();       
     var typeName = reader.GetAttribute("TypeName");
     reader.ReadStartElement();         
     var serializer = new XmlSerializer(GetTypeByName(typeName));
     WrappedObject = serializer.Deserialize(reader);
     reader.ReadEndElement();
  }

  public void WriteXml(XmlWriter writer)
  {         
     writer.WriteAttributeString("TypeName", "", GetTypeByName(WrappedObject));

     var serializer = new XmlSerializer(typeof(WrappedObject));
     serializer.Serialize(writer, WrappedObject);        
  }

I think you need to put attribute above the parent class like this

[XmlInclude(typeof(ChildClass))] 
[Serializable]
public abstract class ParentClass
{
    public abstract string Name { get; set; }
}

in child class you put

[Serializable]
   public class ChildClass: ParentClass
    {   
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM