Which types are supported by XNA's Automatic XNB Serialization?

686 views Asked by At

I've read Shawn Harvgreave's blog entry about automatic serialization and the MSDN article on an overview of the content pipeline, but I couldn't find a list of the types supported.

Quoting MSDN:

Starting with XNA Game Studio 3.1, the serialization of custom data to the .XNB format is done automatically for simple types that do not have an existing content type writer.

I haven't had problems with this until I tried to use a Queue from System.Collections.Generic which I'm guessing isn't supported by the automatic serialization.

So, is there a list of types supported by this? And if it isn't supported, will I need to write my own ContentTypeWriter and ContentTypeReader?

1

There are 1 answers

1
Andrew Russell On BEST ANSWER

Providing a complete list of compatible types is tricky - because the serializer tries to be compatible with custom types it has never seen before. So any list of compatible classes cannot be exhaustive. As Shawn's blog post says:

By default it will serialize all the public fields and properties of your type (assuming they are not read-only).

But let's talk about collection classes. By the above rule, collection classes won't be serialized correctly (when using reflection), because their collection of objects is not a public property (also, indexers aren't supported).

It's interesting to point out why automatically serializing a collection like this isn't a built-in feature. A collection usually implements IEnumerable<T> (like Queue<T> does), which could be serialized. But that's read-only. There's no standard interface like IEnumerable for writing to collections. So there's no way to automatically deserialize them!

Fortunately, XNA provides custom readers/writers for the following generic collection types:

  • Arrays
  • List<T>
  • Dictionary<TKey, TValue>

The serializer automatically uses custom readers/writers when they are available. So if you want it to handle a collection class (like Queue<T>), then you must create your own ContentTypeWriter and ContentTypeReader for it. Fortunately this isn't too hard - see below for an untested implementation.

For a full list of built-in types, see the XNB Format specification. Again this just covers the built-in types. Other types can be supported through reflection or by providing custom reader/writer pairs.


class QueueReader<T> : ContentTypeReader<Queue<T>>
{
    public override bool CanDeserializeIntoExistingObject { get { return true; } }

    protected override Queue<T> Read(ContentReader input, Queue<T> existingInstance)
    {
        int count = input.ReadInt32();
        Queue<T> queue = existingInstance ?? new Queue<T>(count);
        for(int i = 0; i < count; i++)
            queue.Enqueue(input.ReadObject<T>());
        return queue;
    }
}

[ContentTypeWriter]
class QueueWriter<T> : ContentTypeWriter<Queue<T>>
{
    public override string GetRuntimeReader(TargetPlatform targetPlatform)
    {
        return typeof(QueueReader<T>).AssemblyQualifiedName;
    }

    public override bool CanDeserializeIntoExistingObject { get { return true; } }

    protected override void Write(ContentWriter output, Queue<T> value)
    {
        output.Write(value.Count);
        foreach(var item in value)
            output.WriteObject<T>(item);
    }
}

Note that my implementation of GetRuntimeReader here doesn't handle cases where targetPlatform isn't Windows. And you'll need to put these in the right assemblies so you don't get dependency issues.