How to Serialize Interfaces in .NET

I’m working on some final touches for SlimTune’s next version, and one of them involves persisting the launcher settings between application runs. Launching is handled by an interface ILauncher, which can be set to any number of things via a reflected list of inherited types. A PropertyGrid is used to configure the settings, and all the underlying code ever sees is the interface. SlimTune’s a plugin based C# app, and this is all pretty standard.

When it came to persisting this data across sessions, I figured it’d be no big deal — I’ll just serialize the object out to isolated storage, and deserialize it again when I need it. There’s one hang-up, though. Serializers (or at least XmlSerializer) can’t handle interfaces! Worse still, the so-called solutions I found online were utterly ludicrous. It turns out this is actually an incredibly easy problem to solve, and mainly involves stopping and thinking about what you’re doing for about five seconds.

Alright, so we can’t serialize an interface, but we can serialize any concrete type. Same goes for the deserialization process. The answer is to simple: store the concrete type with the serialized data.

//save the launcher configuration to isolated storage
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
using(var configFile = new IsolatedStorageFileStream(ConfigFile, FileMode.Create, FileAccess.Write, isoStore))
	var launcherType = m_launcher.GetType();
	//write the concrete type so we know what to deserialize
	string launcherTypeName = launcherType.AssemblyQualifiedName;
	var sw = new StreamWriter(configFile);

	//write the object itself
	var serializer = new XmlSerializer(launcherType);
	serializer.Serialize(sw, m_launcher);

We simply ask the interface to give us its real type, and record it to the file before serializing. Okay, so the result won’t be a legal XML file, but how often is that actually a problem? Now the deserialize side of the equation:

//try and load a launcher configuration from isolated storage
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
using(var configFile = new IsolatedStorageFileStream(ConfigFile, FileMode.Open, FileAccess.Read, isoStore))
	//read the concrete type to deserialize
	var sr = new StreamReader(configFile);
	var launcherTypeName = sr.ReadLine();
	var launcherType = Type.GetType(launcherTypeName, true);

	//read the actual object
	XmlSerializer serializer = new XmlSerializer(launcherType);
	m_launcher = (ILauncher) serializer.Deserialize(sr);

Reversing things, we first read the type that was written to file, and reconstruct the actual concrete type that goes with that string. Then we know exactly what to deserialize, and XmlSerializer is happy to oblige.

Now that wasn’t so hard, was it?


6 thoughts on “How to Serialize Interfaces in .NET

    1. A tag? I would prefer to embed the type into the XML but the only way I can think of doing that is to serialize to and from an XmlDocument and modify the doc elements manually.

  1. I havnt done much with XmlSerializer. I wrote my own equivelant, which has better handling for things like this(plus the main reason, it has good versioning support for backward/forward compatability of art assets).

    But isnt it possible to have XmlSerializer output an XML fragment to an XmlWriter? That way you could create a root element, with an attribute which specifies the type.

    1. XmlSerializer can handle an XmlWriter just fine. What’s weird is getting XmlWriter hooked up to an XmlDocument. There’s a couple different approaches but once you’ve got that working, you could simply add an attribute to the top node with the type.

      I’m just saving a private settings file to isolated storage file, so the fact that I’m generally a file that isn’t actually XML anymore doesn’t matter. KISS, right?

  2. Yeah I guess. Just doesn’t feel right. I would have spent some extra time to make it neat and tidy. But then I have lots of time to write software “The Right Way”, if I never finish what I am working on I will be perfectly happy:-)

    Settings files should probably remain compatible across version, so unless you want to break that compatibility you(or we if there are other contributors) will be stuck with the current system.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s