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

*爱你&永不变心* 提交于 2019-12-06 11:29:31

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!