In .Net 4 or 4.5, how would you design a serializable class that contains an instance of one class from a set of classes? For instance, suppose I have a Garage class, which can hold an instance of any "vehicle" type classes, say Car, Boat, Motorcycle, Motorhome. But the Garage can only hold an instance of one of those classes. I have tried a few different ways of doing this, but my problem is to make it serializable.
Here is a starting example where there is only one option for the instance in the Garage class. You should be able to plug it right into a new console app and try it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Patterns
{
[Serializable()]
public class Garage
{
private Vehicle _MyVehicle;
public Garage()
{
}
public string GarageOwner { get; set; }
public Vehicle MyVehicle
{
get { return _MyVehicle; }
set { _MyVehicle = value; }
}
}
[Serializable()]
public class Vehicle
{
public string VehicleType { get; set; }
public int VehicleNumber { get; set; }
}
class Serializer
{
static string _StartupPath = @"C:\Projects\Patterns\Data\";
static string _StartupFile = "SerializerTest.xml";
static string _StartupXML = _StartupPath + _StartupFile;
static void Main(string[] args)
{
Console.Write("Press w for write. Press r for read:");
ConsoleKeyInfo cki = Console.ReadKey(true);
Console.WriteLine("Pressed: " + cki.KeyChar.ToString());
if (cki.KeyChar.ToString() == "w")
{
Garage MyGarage = new Garage();
MyGarage.GarageOwner = "John";
MyGarage.MyVehicle = new Vehicle();
MyGarage.MyVehicle.VehicleType = "Car";
MyGarage.MyVehicle.VehicleNumber = 1234;
WriteGarageXML(MyGarage);
Console.WriteLine("Serialized");
}
else if (cki.KeyChar.ToString() == "r")
{
Garage MyGarage = ReadGarageXML();
Console.WriteLine("Deserialized Garage owned by " + MyGarage.GarageOwner);
}
Console.ReadKey();
}
public static void WriteGarageXML(Garage pInstance)
{
XmlSerializer writer = new XmlSerializer(typeof(Garage));
using (FileStream file = File.OpenWrite(_StartupXML))
{
writer.Serialize(file, pInstance);
}
}
public static Garage ReadGarageXML()
{
XmlSerializer reader = new XmlSerializer(typeof(Garage));
using (FileStream input = File.OpenRead(_StartupXML))
{
return reader.Deserialize(input) as Garage;
}
}
}
}
To make a Java object serializable you implement the java. io. Serializable interface. This is only a marker interface which tells the Java platform that the object is serializable.
The easiest way to make a class serializable is to mark it with the SerializableAttribute as follows. The following code example shows how an instance of this class can be serialized to a file. MyObject obj = new MyObject(); obj. n1 = 1; obj.
You just add the implements Serializable clause to your class declaration like this: public class MySerializableClass implements Serializable { ... } You don't have to write any methods. The serialization of instances of this class are handled by the defaultWriteObject method of ObjectOutputStream .
Based on another SO article, this is what finally worked for me. It can serialize and deserialize cleanly. Using this example, I can design a "tree" of objects which have options for what is used. So this could be extended that a Car can have one Engine of several different Engine type classes and one Interior of several different Interior types... and so on.
The code began to work by adding the statements below like: [XmlInclude(typeof(Car))]
But please let me know if there are better ways!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Patterns
{
public class Garage
{
private Vehicle _MyVehicle;
public Garage()
{
}
public string GarageOwner { get; set; }
public Vehicle MyVehicle
{
get { return _MyVehicle; }
set { _MyVehicle = value; }
}
}
[XmlInclude(typeof(Car))]
[XmlInclude(typeof(Boat))]
[XmlInclude(typeof(Motorcycle))]
[XmlInclude(typeof(Motorhome))]
public abstract class Vehicle
{
public string VehicleType { get; set; }
public int VehicleNumber { get; set; }
}
public class Car : Vehicle
{
public int Doors { get; set; }
}
public class Boat : Vehicle
{
public int Engines { get; set; }
}
public class Motorcycle : Vehicle
{
public int Wheels { get; set; }
}
public class Motorhome : Vehicle
{
public int Length { get; set; }
}
class Serializer
{
static string _StartupPath = @"C:\Projects\Patterns\Data\";
static string _StartupFile = "SerializerTest.xml";
static string _StartupXML = _StartupPath + _StartupFile;
static void Main(string[] args)
{
Console.Write("Press w for write. Press r for read:");
ConsoleKeyInfo cki = Console.ReadKey(true);
Console.WriteLine("Pressed: " + cki.KeyChar.ToString());
if (cki.KeyChar.ToString() == "w")
{
Garage MyGarage = new Garage();
MyGarage.GarageOwner = "John";
Car c = new Car();
c.VehicleType = "Lexus";
c.VehicleNumber = 1234;
c.Doors = 4;
MyGarage.MyVehicle = c;
WriteGarageXML(MyGarage);
Console.WriteLine("Serialized");
}
else if (cki.KeyChar.ToString() == "r")
{
Garage MyGarage = ReadGarageXML();
Console.WriteLine("Deserialized Garage owned by " + MyGarage.GarageOwner);
}
Console.ReadKey();
}
public static void WriteGarageXML(Garage pInstance)
{
XmlSerializer writer = new XmlSerializer(typeof(Garage));
using (FileStream file = File.OpenWrite(_StartupXML))
{
writer.Serialize(file, pInstance);
}
}
public static Garage ReadGarageXML()
{
XmlSerializer reader = new XmlSerializer(typeof(Garage));
using (FileStream input = File.OpenRead(_StartupXML))
{
return reader.Deserialize(input) as Garage;
}
}
}
}
To serialize sequences of serializable classes you can use Generic list instances.
I generated this
<?xml version="1.0"?>
<Garage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GarageOwner>John</GarageOwner>
<MyVehicles>
<Vehicle>
<VehicleType>Car</VehicleType>
<VehicleNumber>1234</VehicleNumber>
</Vehicle>
<Vehicle>
<VehicleType>Boat</VehicleType>
<VehicleNumber>56234</VehicleNumber>
</Vehicle>
</MyVehicles>
</Garage>
By simply converting the MyVehicle to a generic list
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace Patterns
{
[Serializable()]
public class Garage
{
public string GarageOwner { get; set; }
public List<Vehicle> MyVehicles { get; set; }
}
[Serializable()]
public class Vehicle
{
public string VehicleType { get; set; }
public int VehicleNumber { get; set; }
}
class Serializer
{
static string _StartupPath = @"C:\temp\";
static string _StartupFile = "SerializerTest.xml";
static string _StartupXML = _StartupPath + _StartupFile;
static void Main(string[] args)
{
Console.Write("Press w for write. Press r for read:");
ConsoleKeyInfo cki = Console.ReadKey(true);
Console.WriteLine("Pressed: " + cki.KeyChar.ToString());
if (cki.KeyChar.ToString() == "w")
{
Garage MyGarage = new Garage();
MyGarage.GarageOwner = "John";
// Create some vehicles
var myVehicle1 = new Vehicle();
myVehicle1.VehicleType = "Car";
myVehicle1.VehicleNumber = 1234;
var myVehicle2 = new Vehicle();
myVehicle2.VehicleType = "Boat";
myVehicle2.VehicleNumber = 56234;
// Create a new instance and add the vehicles
MyGarage.MyVehicles = new List<Vehicle>()
{
myVehicle1,
myVehicle2
};
WriteGarageXML(MyGarage);
Console.WriteLine("Serialized");
}
else if (cki.KeyChar.ToString() == "r")
{
Garage MyGarage = ReadGarageXML();
Console.WriteLine("Deserialized Garage owned by " + MyGarage.GarageOwner);
}
Console.ReadKey();
}
public static void WriteGarageXML(Garage pInstance)
{
XmlSerializer writer = new XmlSerializer(typeof(Garage));
using (FileStream file = File.OpenWrite(_StartupXML))
{
writer.Serialize(file, pInstance);
}
}
public static Garage ReadGarageXML()
{
XmlSerializer reader = new XmlSerializer(typeof(Garage));
using (FileStream input = File.OpenRead(_StartupXML))
{
return reader.Deserialize(input) as Garage;
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With