Click here to Skip to main content

Get rid of XmlInclude when using XmlSerializer

A solution presented in C# .NET 3.5 using the latest in LINQ technology.
Sign Up to vote bad good
Add a reason or comment to your vote: x
Votes of 3 or less require a comment
See more: .NET3.5C#XML

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.

// use reflection to get all derived types
var knownTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
    t => typeof(Car).IsAssignableFrom(t) || typeof(
    Wheel).IsAssignableFrom(t) || typeof(Door).IsAssignableFrom(t)).ToArray();
 
// prepare to serialize a car object
XmlSerializer serializer = new XmlSerializer(typeof(Car), knownTypes);
 
// serialize!
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:

// use reflection to get all derived types
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);
 
// prepare to serialize a car object
XmlSerializer serializer = new XmlSerializer(typeof(Car), knownTypes.ToArray());
 
// the rest is same...</type></type>

That is it!

Posted 10 Jan '10
Edited 29 Jul '11

Comments
VMAtm - 4 Aug '11
Reason for my vote of 1 you can do better sample.

Sign Up to vote bad good
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Alternative 2

How would you do this, if objects included inside one of the serialized objects was an abstract class? E.g.:

abstract class Base
{
    public int x;
}
 
class A : Base
{
    public int y;
}
 
class B : A
{
    public int z;
}
 
class SomeOtherClass
{
    public string s;
}
 
class SerializingClass
{
    public int w;
    public Base myB1;
    public Base myB2;
}
 
//AND you have an object
var sc = new SerializingClass{
   w = 10,
   myB1 = new B{ x = 1, y, 2, z = 3},
   myB2 = new A{ x = 10, y=20 }
};

How would you use your method to add just Base, A, B, and not SomeOtherClass without knowing the inner classes and derived classes held within your top level class which you request the serializer from? If you must know all of this, then I'd feel that this method is limited to shallow class structs and the XML attribute method works better (for this case).

  Permalink  
Comments
johannesnestler - 11 Aug '11
Hmm, maybe I just don't get it: OP wrote: typeof(Car).IsAssignableFrom(t), so in your case just use: typeof(Base)... and SomeOtherClass wouldn't go to the serializer, would it? And: I didn't check it now, but I think the serializer does nothing with the additional type descriptions if you don't give it objects of this type to serialize.
Sign Up to vote bad good
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Alternative 3

Serializable Extra Types for .NET 4[^]

Does what you are looking for using attributes.

  Permalink  
Sign Up to vote bad good
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Alternative 4

The above solution made me grin as it helped me solved my serialization puzzle. However, if you have an extensible format with components spread over multiple assemblies, this solution may not pick up all the types.

I brute force it as follows:

List<type> knownTypes = new List<type>();
 
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
    knownTypes.AddRange(Assembly.GetExecutingAssembly().GetTypes().Where(
    t => typeof(XMLBinaryPackageInfo).IsAssignableFrom(t)));
}

My rationale is that this code is unlikely to be called often enough to worry about enumerating such a potentially vast number of types. I don't cache this stuff but you can keep track of assembly loading / unloading if you must. Mileage may vary!

  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Your Filters
Interested
Ignored
     
  1. Christian Graus (1,099)
  2. SAKryukov (591)
  3. CRDave1988 (432)
  4. Abhinav S (215)
  1. SAKryukov (10,303)
  2. Christian Graus (7,108)
  3. OriginalGriff (5,156)
  4. Abhinav S (4,550)
  5. thatraja (4,371)

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionFor deep and complex class structures PinmemberBob Sandberg5:49 29 Jul '11  
AnswerRe: For deep and complex class structures PinmemberDaniel Gidman6:39 1 Aug '11  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.


Advertise | Privacy | Mobile
Web01 | 2.5.120210.1 | Last Updated 17 Nov 2011
Copyright © CodeProject, 1999-2012
All Rights Reserved. Terms of Use
Layout: fixed | fluid