How to implement Xml Serialization with inherited classes in C#

19,071

Solution 1

Unfortunately, you need to tell the XmlSerializer the classes you intend to serialize or deserialize using the XmlArrayItem() attribute. Each different type also needs its own element name. For example:

public class ComponentDerviedClass1: Component
public class ComponentDerivedClass2: Component
public class ComponentDerivedClass3: Component

// ...

public class ComponentsCollection
{
    [XmlArray("Components")]
    [XmlArrayItem("ComponentDerivedClass1", typeof(ComponentDerivedClass1))]
    [XmlArrayItem("ComponentDerivedClass2", typeof(ComponentDerivedClass2))]
    [XmlArrayItem("ComponentDerivedClass3", typeof(ComponentDerivedClass3))]
    public List<Component> Components
    {
        // ...
    }
}

This would read an XML file like:

<?xml version="1.0" encoding="utf-8" ?>
<ComponentsCollection>    
  <Components>
     <ComponentDerivedClass1>
         <!-- ... -->
     </ComponentDerivedClass1>
     <ComponentDerivedClass2>
         <!-- ... -->
     </ComponentDerivedClass2>
     <ComponentDerivedClass3>
         <!-- ... -->
     </ComponentDerivedClass3>
   </Components>  
</ComponentsCollection>

Multiple instances of each element can be present (or none).

Solution 2

Two options for different scenrios: tell the base-class

[XmlInclude(typeof(DBComponent))]
public class Component
{
    private string name = string.Empty;
    private string description = string.Empty;  
}

Or: tell the collection:

[XmlArray]
[XmlArrayItem("Component", typeof(Component))]
[XmlArrayItem("DBComponent", typeof(DBComponent))]
public List<Component> Components {...}

Actually, you can also use [XmlElement(...)] in place of [XmlArrayItem] if you don't want the outer node (Components). Also: you don't need [Serializable].

Share:
19,071
liorafar
Author by

liorafar

Updated on June 17, 2022

Comments

  • liorafar
    liorafar almost 2 years

    I have two classes : base class name Component and inheritd class named DBComponent

    [Serializable]
    public class Component
    {
        private string name = string.Empty;
        private string description = string.Empty;  
    }
    
    [Serializable]
    public class DBComponent : Component
    {
        private List<string> spFiles = new List<string>();
    
        // Storage Procedure Files
        [XmlArrayItem("SPFile", typeof(string))]
        [XmlArray("SPFiles")]
        public List<string> SPFiles
        {
            get { return spFiles; }
            set { spFiles = value; }
        }
    
        public DBComponent(string name, string description)
            : base(name, description)
        { }
    }  
    
    [Serializable]
    public class ComponentsCollection
    {
      private static ComponentsCollection instance = null;
      private List<Component> components = new List<Component>();
    
      public List<Component> Components
      {
          get { return components; }
          set 
          { 
                components = value; 
          }
      }
    
       public static ComponentsCollection GetInstance()
        {
            if (ccuInstance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                        PopulateComponents();
                }
            }
            return instance;
        }
    
        private static void PopulateComponents()
        {
            instance = new CCUniverse();
            XmlSerializer xs = new XmlSerializer(instance.GetType());
            instance = xs.Deserialize(XmlReader.Create("Components.xml")) as ComponentsCollection;
        }
    }
    

    }

    I want read\write from a Xml file. I know that I need to implement the Serialization for DBComponent class otherwise it will not read it.But i cannot find any simple article for that. all the articles that I found were too complex for this simple scenario.
    The Xml file looks like this:

    <?xml version="1.0" encoding="utf-8" ?>
      <ComponentsCollection>    
        <Components>
                <DBComponent Name="Tenant Historical Database" Description="Tenant Historical Database">
                        <SPFiles>
                            <SPFile>Setup\TenantHistoricalSP.sql</SPFile>
                        </SPFiles>
                </DBComponent>
                <Component Name="Agent" Description="Desktop Agent" />
            </Components>  
      </ComponentsCollection>
    

    Can someone please give me a simple example of how to read this kind of xml file and what should be implemented ?

    Thanks
    Lior

  • The One
    The One over 2 years
    Note for myself: What (I think) Marc Gravell is saying is that you can leave out the "Components" node from the XML if you remove [XmlArray] and change each of the [XmlArrayItem] attributes to [XmlElement] on the Components list