Solution: Serializing as XML

Take a look at the solution to the previous challenge.

Problem statement

Creates a list of shapes, uses serialization to save it to the filesystem using XML, and then deserializes it back:

Press + to interact
// create a list of Shapes to serialize
List<Shape> listOfShapes = new()
{
new Circle { Colour = "Red", Radius = 2.5 },
new Rectangle { Colour = "Blue", Height = 20.0, Width = 10.0 },
new Circle { Colour = "Green", Radius = 8.0 },
new Circle { Colour = "Purple", Radius = 12.3 },
new Rectangle { Colour = "Blue", Height = 45.0, Width = 18.0 }
};

Shapes should have a read-only property named Area so that when deserialized, it can output a list of shapes, including their areas, as shown here:

Press + to interact
List<Shape> loadedShapesXml =
serializerXml.Deserialize(fileXml) as List<Shape>;
foreach (Shape item in loadedShapesXml)
{
WriteLine("{0} is {1} and has an area of {2:N2}",
item.GetType().Name, item.Colour, item.Area);
}

Step-by-step solution

Let’s look at our solution by comprehensively understanding it.

Let’s have a look at Program.cs file:

Press + to interact
using Packt.Shared; // Circle, Rectangle, Shape
using System.Xml.Serialization; // XmlSerializer
using static System.Environment;
using static System.IO.Path;
// create a file path to write to
string path = Combine(CurrentDirectory, "shapes.xml");
// create a list of Shape objects to serialize
List<Shape> listOfShapes = new()
{
new Circle { Colour = "Red", Radius = 2.5 },
new Rectangle { Colour = "Blue", Height = 20.0, Width = 10.0 },
new Circle { Colour = "Green", Radius = 8 },
new Circle { Colour = "Purple", Radius = 12.3 },
new Rectangle { Colour = "Blue", Height = 45.0, Width = 18.0 }
};
// create an object that knows how to serialize and deserialize
// a list of Shape objects
XmlSerializer serializerXml = new(listOfShapes.GetType());
WriteLine("Saving shapes to XML file:");
using (FileStream fileXml = File.Create(path))
{
serializerXml.Serialize(fileXml, listOfShapes);
}
WriteLine("Loading shapes from XML file:");
List<Shape>? loadedShapesXml = null;
using (FileStream fileXml = File.Open(path, FileMode.Open))
{
loadedShapesXml =
serializerXml.Deserialize(fileXml) as List<Shape>;
}
if (loadedShapesXml == null)
{
WriteLine($"{nameof(loadedShapesXml)} is empty.");
}
else
{
foreach (Shape item in loadedShapesXml)
{
WriteLine($"{item.GetType().Name} is {item.Colour} and has an area of {item.Area:N2}");
}
}

In this file, we are initializing a List<Shape> named listOfShapes. The list is populated with instances of Circle and Rectangle objects, representing shapes. These shapes are specified with various properties, such as color, radius, height, and width. Then, we created objects that know how to serialize and deserialize a list of shape objects. After that, we check if the shapes were successfully loaded from the XML file. If they were loaded, it prints information about each shape, including its type, color, and area. If no shapes were loaded, it prints a message indicating that loadedShapesXml is empty, meaning no shapes were deserialized.

Let’s have a look at Shape.cs file:

Press + to interact
using System.Xml.Serialization;
namespace Packt.Shared;
[XmlInclude(typeof(Circle))]
[XmlInclude(typeof(Rectangle))]
public abstract class Shape
{
public string? Colour { get; set; }
public abstract double Area { get; }
}

Line 1: We import the System.Xml.Serialization namespace to enable ...