views:

67

answers:

1

Consider the following. You have a class that you want to serialize with XmlSerializer which has a public generic method with a type constraint where the type is in a different assembly:

using BarStuff;

namespace FooStuff {
  public class Foo {
    ...
    public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
      ...
    }
  }
}

You wouldn't expect the XmlSerializer to even concern itself with methods, and generally it doesn't. The following both work fine:

//private, serializer doesn't care about it
private T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
  ...
}

//no generic type constraint, serializer also doesn't care about it
public Bar GetBar( string key ) {
  ...
}   

Also, if the type Bar is in the same assembly as Foo then the serializer will also be perfectly happy.

When you execute the first example, if Bar is defined in a separate assembly you will get a runtime exception saying that you need to add a reference to the assembly containing Bar, even if you already have that assembly in your project references. You can get around this by using XmlInclude:

[XmlInclude(typeof(Bar))]
public class Foo {
  public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
    ...
  }
}

However if Bar is not serializable, and there's no reason why it should be, you'll now get a runtime exception the first time it hits something it can't serialize, such as a public property that returns an interface as its type, a class without a parameterless constructor etc.!

Related but not as detailed: http://stackoverflow.com/questions/2361563/xmlserializer-is-throwing-invalidoperationexception-when-using-the-generic-type-c

Also: Microsoft's take on the problem

A: 

Some workarounds:

  • Use a different serializer such as DataContractSerializer
  • Ensure that the types are in the same assembly so that the XmlInclude is unnecessary (yuck)
  • Change Bar to make it serializable (yuck)
  • Avoid having methods of this kind, ie by only serializing DTO type objects and having any such functionality elsewhere
  • This is sneaky and hackish... include a dummy class that is serializable in the same assembly as your type Bar, then XmlInclude that instead, this will make the serializer happy, ie:

Example:

namespace BarStuff {
  //the serializer is perfectly happy with me
  public class DummyBar{}

  //the serializer doesn't like me
  public class Bar{
  ...
  }

  ...
}

using BarStuff;
namespace FooStuff {
  [XmlInclude(typeof(DummyBar))]
  public class Foo {
    public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
      ...
    }
  }
nrkn