How to implement Xml Serialization with inherited classes in C#
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].
liorafar
Updated on June 17, 2022Comments
-
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 over 2 yearsNote 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