Serializing collections of shared resources
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>