2

我已经阅读了 Shawn Harvgreave 的关于自动序列化的博客文章和关于内容管道概述的 MSDN 文章,但我找不到支持的类型列表。

引用 MSDN:

从 XNA Game Studio 3.1 开始,对于没有现有内容类型编写器的简单类型,将自动将自定义数据序列化为 .XNB 格式。

Queue在我尝试使用System.Collections.Generic我猜自动序列化不支持的a 之前,我没有遇到过这个问题。

那么,是否有此支持的类型列表?如果不支持,我是否需要编写自己的ContentTypeWriterand ContentTypeReader

4

1 回答 1

5

提供兼容类型的完整列表很棘手 - 因为序列化程序试图与它以前从未见过的自定义类型兼容。因此,任何兼容类的列表都不能详尽无遗。正如肖恩的博客文章所说:

默认情况下,它将序列化您类型的所有公共字段和属性(假设它们不是只读的)。

但是让我们谈谈集合类。根据上述规则,集合类将无法正确序列化(使用反射时),因为它们的对象集合不是公共属性(也不支持索引器)。

有趣的是,为什么像这样自动序列化集合不是内置功能。一个集合通常实现IEnumerable<T>(就像Queue<T>做的那样),它可以被序列化。但这是只读的。没有像写入集合那样IEnumerable的标准接口。所以没有办法自动反序列化它们!

幸运的是,XNA 为以下通用集合类型提供了自定义读取器/写入器

  • 数组
  • List<T>
  • Dictionary<TKey, TValue>

序列化程序在可用时自动使用自定义读取器/写入器。因此,如果您希望它处理一个集合类(如Queue<T>),那么您必须为它创建自己的ContentTypeWriterContentTypeReader。幸运的是,这并不太难 - 请参阅下面的未经测试的实现。

有关内置类型的完整列表,请参阅XNB 格式规范。同样,这仅涵盖内置类型。其他类型可以通过反射或提供自定义读取器/写入器对来支持。


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);
    }
}

请注意,我在GetRuntimeReader此处的实现不处理targetPlatform不是 Windows 的情况。而且您需要将它们放在正确的程序集中,这样您就不会遇到依赖性问题。

于 2012-10-19T08:20:25.167 回答