XmlSerializerFactory caching issues and leaks
You’d think that after the serious leaks people was hitting with the XmlSerializer, the “new” (in .NET 2.0!!! but which many seem to forget about, just like AVOID doing new XmlTextReader in a PDC keynote) XmlSerializerFactory would do away with those.
Well, bad news: you need to be AS careful as you are with the XmlSerializer in order to avoid those leaks (which are BY DESIGN, BTW). Turns out that apparently the same designer made the same “by design” decisions with the XmlSerializerFactory.
For those not using the factory yet: it was basically meant to be the cache of XmlSerializer types that you had to do manually in the past). If provides a factory method with all the same overloads the XmlSerializer receives and hands you back an instance of a serializer, supposedly caching the generated types (as the documentation says: “Creates typed versions of the XmlSerializer for more efficient serialization.”). You can read my friend Kirk’s blog on how to use the factory.
Nowhere does the documentation mention that depending on which overloads you use, the cache will be in effect or not, JUST LIKE THE “good” old XmlSerializer!!!
VERY easy repro:
class Program
{
static void Main(string[] args)
{
var factory = new XmlSerializerFactory();
var cached1 = factory.CreateSerializer(typeof(Foo));
var cached2 = factory.CreateSerializer(typeof(Foo));
// IT WORKS!!! RIGHT???
Debug.Assert(cached1.GetType() == cached2.GetType());
var serializer1 = factory.CreateSerializer(typeof(Foo), new XmlRootAttribute("foo"));
var serializer2 = factory.CreateSerializer(typeof(Foo), new XmlRootAttribute("foo"));
var serializer3 = factory.CreateSerializer(typeof(Foo), new XmlRootAttribute("foo"));
var serializer4 = factory.CreateSerializer(typeof(Foo), new XmlRootAttribute("foo"));
var allsame = serializer1.GetType() == serializer2.GetType();
allsame &= serializer2.GetType() == serializer3.GetType();
allsame &= serializer3.GetType() == serializer4.GetType();
// FAIL!!!!!
Debug.Assert(allsame);
}
}
public class Foo { }
Now, I understand the myriad of overloads supported by the class are hard to manage, but how hard do you think it is to create a smart cache key that properly compares if the XmlRootAttribute I’m passing, which has only four properties to compare, is the same I passed before and therefore hand me a cached type??
Very dissapointing. I had to (once again) implement this myself (on the ULTIMATE serializable generics dictionary I’ll EVER need to write, which I’ll blog about sometime…). This time I even used dynamic method generation to have a blazingly fast instantiation of the cached generated type :). Another time I said…
Anyway, please vote for the bug so this gets fixed (hopefully it’s not too late for C# 4.0!).
/kzu
/kzu dev↻d