Serialize object with parent class declared
Dear all, when using .Net XmlSerializer.Serialize, i got the problem with code sample as below:-
-----Code sample start-----
public abstract class Vehicle
{
public int Speed;
}
public class Car : Vehicle
{
public int NumberOfDoors;
}
public class Boat : Vehicle
{
public string KeelType;
}
public class Family
{
public Vehicle homeVehicle;
}
class Program
{
static void Main(string[] args)
{
Family objFamily1 = new Family();
Car c = new Car();
c.NumberOfDoors = 4;
c.Speed = 100;
objFamily1.homeVehicle = c;
XmlSerializer s = new XmlSerializer(typeof(Family));
TextWriter w = new StreamWriter("objFamily1.xml");
s.Serialize(w, objFamily1); // <---- "A first chance exception of type 'System.InvalidOperationException' occurred in System.Xml.dll"
w.Close();
}
}
-----Code sample end-----
Code line to perform object serialization works only after changed the class declaration of Family to as following:-
public class Family
{
public Car homeVehicle;
}
Question 1: my problem as there are many different home Vehicle type (like car, boat, etc.), any idea about such scenario? Don't tell my that I have to define different classes to cater for different cases...
I tried some implementation of Xstream in .Net library,
http://code.google.com/p/xstream-dot-net/
http://www.jroller.com/CoBraLorD/date/20050427
and get the result as below:-
-----Code sample start-----
public class Family
{
public Vehicle homeVehicle;
}
...
Family objFamily1 = new Family();
Family objFamily2 = new Family();
Boat b = new Boat();
Car c = new Car();
b.KeelType = "Fast";
b.Speed = 20;
c.NumberOfDoors = 4;
c.Speed = 100;
objFamily1.homeVehicle = b;
objFamily2.homeVehicle = c;
string serialisedObject1 = new XStream().ToXml(objFamily1);
string serialisedObject2 = new XStream().ToXml(objFamily2);
-----Code sample end-----
?serialisedObject1
<Family assembly=\"ObjXMLSubClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">
<homeVehicle type=\"Boat, ObjXMLSubClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">
<KeelType>Fast</KeelType>
<Speed>20</Speed>
</homeVehicle>
</Family>
?serialisedObject2
<Family assembly=\"ObjXMLSubClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">
<homeVehicle type=\"Car, ObjXMLSubClasses, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">
<NumberOfDoors>4</NumberOfDoors>
<Speed>100</Speed>
</homeVehicle>
</Family>
Question 2: It looks fine, but I cannot build solution successfully (only work in debug code lines), btw, where can I found the source code of Xstream.Core.dll?
Seems there is no update since mid-2005...
Réponses
- You need to tell the Serialiser each and every type possible for homeVehicle:
public class Family
{
[XmlElement(typeof(Car))]
[XmlElement(typeof(Boat))]
public Vehicle homeVehicle;
}- Marqué comme réponse.Leon lundi 9 novembre 2009 11:22
Toutes les réponses
- Many thanks for any attention and reply!
Cheers,
.Leon - You need to tell the Serialiser each and every type possible for homeVehicle:
public class Family
{
[XmlElement(typeof(Car))]
[XmlElement(typeof(Boat))]
public Vehicle homeVehicle;
}- Marqué comme réponse.Leon lundi 9 novembre 2009 11:22
- Question1) Here's a Vehicle class that you can use.
public interface IVehicle
{
int Speed { get; set; }
}
public abstract class AVehicle : IVehicle
{
public int Speed { get; set; }
}
public class Vehicle : AVehicle { }
Question 2) I guess no updates are out there to be had.
Mark the best replies as answers. "Fooling computers since 1971." - I don't see what IVehicle and AVehicle add. You still have to mark the homeVehicle field with XmlElement attributes.
You need to tell the Serialiser each and every type possible for homeVehicle:
public class Family
{
[XmlElement(typeof(Car))]
[XmlElement(typeof(Boat))]
public Vehicle homeVehicle;
}
That is one scenario that you want ot avoid at any and all costs.
You want the class to be consumed without having to limit the type to who and what can consume it.
You could if you want, but it would make adding new Vehicle classes a real problem.
The serializer had a problem with the original abstract class, Vehicle.
You cannot create an instance, de-serialize, of an abstract class, and the compiler knows that.
IVehicle is intended to get the OP to code to composition, not inheritance. Ditto for AVehicle.
Mark the best replies as answers. "Fooling computers since 1971."- The serializer doesn't have a problem with Vehicle because it's abstract.
It has a problem with Vehicle because it needs to know the exact type of the object.
Remove the 'abstract' modifier from Vehicle and you still get the same error.
I still don't see how IVehicle and AVehicle will solve that.
Which type exactly would you put for the 'homeVehicle' field?
When you say "code for composition, not inheritance", you mean Car having a Vehicle member instead of inheriting from Vehicle?
And then, you end with several independent classes which you cannot put in the same 'homeVehicle' field.
Maybe I don't see something obvious. - Dear Louis.fr, really appreciate for your reply, my problem resolved by the simple but effective note!
One thing to share, as some other class members also are initially defined as Vehicle, same case to homeVehicle, we cannot apply the same rule to these members, and no problem with XmlSerializer.Serialize.
So I decide to define some never used class member just host the Xml rule for serialization, sample code as below:-
public class Family
{
[XmlElement(typeof(Car))]
[XmlElement(typeof(Boat))]
public Vehicle _typeVehicle;
public Vehicle homeVehicle;
public Vehicle homeVehicleWife;
[XmlArray("Childs"), XmlArrayItem("ChildVehicle", typeof(Vehicle))]
public List<Vehicle> homeVehicleChilds = new List<Vehicle>();
} Dear Rudedog2, thx for your reply, don't have to try your approach, seems add Xml rule is easier for my scenario.
I didn't know you could do that.
Seems like the serializer uses the attributes on _typeVehicle for every Vehicle field.
Except that the field on which you put the attributes is serialized using the name of the type. The other fields are serialized using the names of the fields and an xsi:type attribute.- Exactly! The ultimate target is after some XML massaging, XML data serialized from object could be interop b/w Java and .Net.
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<homeVehicle xsi:type="Boat">
<Speed>20</Speed>
<KeelType>Fast</KeelType>
</homeVehicle>
<homeVehicleWife xsi:type="Car">
<Speed>100</Speed>
<NumberOfDoors>4</NumberOfDoors>
</homeVehicleWife>
<Childs>
<ChildVehicle xsi:type="Boat">
<Speed>20</Speed>
<KeelType>Fast</KeelType>
</ChildVehicle>
<ChildVehicle xsi:type="Car">
<Speed>100</Speed>
<NumberOfDoors>4</NumberOfDoors>
</ChildVehicle>
</Childs>
</Family>

