Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Xml Serialization with inherited classes in C#

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

like image 666
liorafar Avatar asked Sep 02 '12 15:09

liorafar


People also ask

What is the correct way of using XML serialization?

As with the CreatePo method, you must first construct an XmlSerializer, passing the type of class to be deserialized to the constructor. Also, a FileStream is required to read the XML document. To deserialize the objects, call the Deserialize method with the FileStream as an argument.

Can serializable class inherited in C#?

You must explicitly mark each derived class as [Serializable] . If, however, you mean the ISerializable interface, then yes: interface implementations are inherited, but you need to be careful - for example by using a virtual method so that derived classes can contribute their data to the serialization.

What is the difference between binary serialization and XML serialization?

Xml Serializer serializes only public member of object but Binary Serializer serializes all member whether public or private. In Xml Serialization, some of object state is only saved but in Binary Serialization, entire object state is saved.

Why do we use XML serializer class?

XmlSerializer Class. Serializes and deserializes objects into and from XML documents. The XmlSerializer enables you to control how objects are encoded into XML. XML serialization is the process of converting an object's public properties and fields to a serial format (in this case, XML) for storage or transport.


2 Answers

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).

like image 156
akton Avatar answered Sep 20 '22 19:09

akton


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].

like image 31
Marc Gravell Avatar answered Sep 16 '22 19:09

Marc Gravell