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.
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
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);
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) ||
XmlSerializer serializer = new XmlSerializer(typeof(Car), knownTypes.ToArray());
That is it!