Serializing collections of shared resources

Originally posted to Shawn Hargreaves Blog on MSDN, Thursday, November 20, 2008

Tomasz emailed me a good question today:

"Very good reading about IntermediateSerializer. I was wondering however if this is possible to use it to serialize a Collection of elements which shall be serialized as shared resources. When I use [ContentSerializer(SharedResource = true)] for a Collection the collection itself is treated as a shared resource. This is a problem since I could end up with multiple "copies" of objects serialized, some of them as shared resources and some of them in the collection."

First the bad news: there is no way to do this using attributes.

But the good news is you can do it by making a custom class for your list of shared resources:

    class SharedResourceList<T> : List<T> { }

and then implementing a custom ContentTypeSerializer for this new class:

    [ContentTypeSerializer]
    class SharedResourceListSerializer<T> : ContentTypeSerializer<SharedResourceList<T>>
    {
        static ContentSerializerAttribute itemFormat = new ContentSerializerAttribute()
        {
            ElementName = "Item"
        };

protected override void Serialize(IntermediateWriter output, SharedResourceList<T> value, ContentSerializerAttribute format) { foreach (T item in value) { output.WriteSharedResource(item, itemFormat); } }
protected override SharedResourceList<T> Deserialize(IntermediateReader input, ContentSerializerAttribute format, SharedResourceList<T> existingInstance) { if (existingInstance == null) existingInstance = new SharedResourceList<T>(); while (input.MoveToElement(itemFormat.ElementName)) { input.ReadSharedResource(itemFormat, (T item) => existingInstance.Add(item)); } return existingInstance; } }

With the above code, this test:

    SharedResourceList<string> test = new SharedResourceList<string>();
test.Add("elf"); test.Add("23"); using (XmlWriter writer = XmlWriter.Create("out.xml"))
IntermediateSerializer.Serialize(writer, test, null);

produces this XML:

    <?xml version="1.0" encoding="utf-8"?>
    <XnaContent>
      <Asset Type="SharedResourceList[string]">
        <Item>#Resource1</Item>
        <Item>#Resource2</Item>
      </Asset>
      <Resources>
        <Resource ID="#Resource1" Type="string">elf</Resource>
        <Resource ID="#Resource2" Type="string">23</Resource>
      </Resources>
    </XnaContent>

2010 note: this article describes how to customize IntermediateSerializer XML. To do the same thing for binary .xnb serialization, see here.

Blog index   -   Back to my homepage