Как сделать сериализуемый класс, содержащий экземпляр одного класса из набора классов

В .Net 4 или 4.5, как бы вы создали сериализуемый класс, который содержит экземпляр одного класса из набора классов? Например, предположим, что у меня есть класс Garage, который может содержать экземпляр классов типа "автомобиль", например, "Автомобиль", "Лодка", "Мотоцикл", "Автодома". Но гараж может содержать только экземпляр одного из этих классов. Я пробовал несколько разных способов сделать это, но моя проблема состоит в том, чтобы сделать его сериализуемым.

Вот начальный пример, в котором есть только один вариант для экземпляра в классе Garage. Вы должны подключить его прямо к новому консольному приложению и попробовать его.

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:");
 ************** 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;
 }
 }
 }
}
2 ответа

Основываясь на другой статье тут, это то, что окончательно сработало для меня. Он может сериализоваться и десериализоваться чисто. Используя этот пример, я могу создать "дерево" объектов, которые имеют опции для того, что используется. Таким образом, это может быть расширено, что автомобиль может иметь один Двигатель нескольких классов типов двигателей и один интерьер нескольких разных типов салона... и т.д.

Код начал работать, добавив следующие инструкции: [XmlInclude (typeof (Car))]

Но, пожалуйста, дайте мне знать, есть ли лучшие способы!

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:");
 ************** 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;
 }
 }
 } 
}


Для сериализации последовательностей сериализуемых классов вы можете использовать экземпляры общего списка.

Я создал этот

<!--?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>

Просто преобразуя MyVehicle в общий список

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:");
 ************** 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;
 }
 }
 }
}
</vehicle></vehicle>

licensed under cc by-sa 3.0 with attribution.