Ever tried to serialize a class using XmlSerializer
and bumped into an exception telling you to use XmlInclude
? Well, this tip will use Reflection to automatically dispel such problems.
Using the XmlInclude
attribute on a base class to recognize its derived classes is somewhat problematic as it goes against principles of Object Oriented programming in which base classes are not supposed to know of their derived classes. It tends to be high maintenance because new derived classes may appear long after the base class is written. Also, it may be the case that the programmer doesn't even have access to change the base class to add support for his newly written derived class.
So, here is the solution, presented in C# .NET 3.5 using the latest in LINQ technology.
Let's say you have three base classes named Car
, Wheel
, and Door
. From these three classes, a big tree of derived classes might grow. This code will allow you to use the default XmlSerializer
without using XmlInclude
and without any kind of config files or whatever.
var knownTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
t => typeof(Car).IsAssignableFrom(t) || typeof(
Wheel).IsAssignableFrom(t) || typeof(Door).IsAssignableFrom(t)).ToArray();
XmlSerializer serializer = new XmlSerializer(typeof(Car), knownTypes);
TextWriter textWriter = new StreamWriter(@"car.xml", false, Encoding.UTF8);
serializer.Serialize(textWriter, car);
textWriter.Close();
To run this in .NET 2.0, you need to replace the LINQ part with a foreach
loop, and the 'var'
statement with the real variable type. So the first lines would look like this:
List<type> knownTypes = new List<type>();
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes())
if (typeof(Car).IsAssignableFrom(t) ||
typeof(Wheel).IsAssignableFrom(t) ||
typeof(Door).IsAssignableFrom(t))
knownTypes.Add(t);
XmlSerializer serializer = new XmlSerializer(typeof(Car), knownTypes.ToArray());
That is it!