Wednesday, August 24, 2011

Dictionary of shared resources for serializing in XNA

Introduction

Contents

This is a class built on the articles of Shawn Hargreaves for using the IntermediateSerializer class to serialize collections of shared resources. In his article he only does the List<T> collection, but I had the need to serialize a Dictionary<T,K> instead, and maybe someone else will need it at some point, so here it is.

Background

The class is to be used with the IntermediateSerializer. It’s a class for serializing data to XML in XNA, and though it only works on the windows platform, it’s easier to use and has a lot more flexibility than the XmlSerializer. Introduction to the IntermediateSerializer can be found here, and a more extensive explanation can be found here. Following that, you might want to check out how to write your own ContentTypeSerializer, and specifically, how to do it for a collection of shared resources.

Code

As you have seen in the example about collections of shared resources, Shawn only deals with the List class, leaving us to work through the rest. Well, here is a Dictionary class with the values as shared resources.

Dictionary evolves to… SharedResourceDictionary!

The shared resource dictionary is nothing more than an empty wrapper:

Code Snippet
  1. class SharedResourceDictionary<K, T> :
  2.     Dictionary<K, T>
  3. {    }

SharedResourceDictionarySerializer

This is where the serializing gets done. As a side note, you don’t need to do anything special to get the SharedResourceDictionary to use the SharedResourceDictionarySerializer, just by having both classes in your project it’s fine.

Code Snippet
  1. [ContentTypeSerializer]
  2. class SharedResourceDictionarySerializer<T, K> :
  3.     ContentTypeSerializer
  4.         <SharedResourceDictionary<T, K>>
  5. {
  6.     static ContentSerializerAttribute itemFormat =
  7.         new ContentSerializerAttribute()
  8.     {
  9.         ElementName = "Item"
  10.     };
  11.  
  12.     static ContentSerializerAttribute keyFormat =
  13.         new ContentSerializerAttribute()
  14.     {
  15.         ElementName = "Key"
  16.     };
  17.  
  18.     static ContentSerializerAttribute valueFormat =
  19.         new ContentSerializerAttribute()
  20.     {
  21.         ElementName = "Value"
  22.     };
  23.  
  24.  
  25.  
  26.     protected override void Serialize(
  27.         IntermediateWriter output,
  28.         SharedResourceDictionary<T, K> value,
  29.         ContentSerializerAttribute format)
  30.     {
  31.             foreach (KeyValuePair<T, K> item in value)
  32.         {
  33.             output.Xml.WriteStartElement(
  34.                 itemFormat.ElementName);
  35.  
  36.             output.WriteObject(
  37.                 item.Key,
  38.                 keyFormat);
  39.  
  40.             output.WriteSharedResource(
  41.                 item.Value,
  42.                 valueFormat);
  43.  
  44.             output.Xml.WriteEndElement();
  45.         }
  46.     }
  47.  
  48.  
  49.     protected override SharedResourceDictionary<T, K>
  50.         Deserialize(
  51.         IntermediateReader input,
  52.         ContentSerializerAttribute format,
  53.         SharedResourceDictionary<T, K> existingInstance)
  54.     {
  55.         if (existingInstance == null)
  56.         {
  57.             existingInstance =
  58.                 new SharedResourceDictionary<T, K>();
  59.         }
  60.  
  61.         while (input.MoveToElement(itemFormat.ElementName))
  62.         {
  63.             T key;
  64.  
  65.             input.Xml.ReadToDescendant(
  66.                 keyFormat.ElementName);
  67.  
  68.             key = input.ReadObject<T>(keyFormat);
  69.  
  70.             input.Xml.ReadToNextSibling(
  71.                 valueFormat.ElementName);
  72.  
  73.             input.ReadSharedResource<K>(
  74.                 valueFormat,
  75.                 (K value) =>
  76.             {
  77.                 existingInstance.Add(key, value);
  78.             });
  79.             input.Xml.ReadEndElement();
  80.         }
  81.  
  82.         return existingInstance;
  83.     }
  84. }

Sorry about the “strung out” format of the code, otherwise the blog settings compact it into an unreadable mess.

Calling the serializer

To use this code, we have a dictionary we want to serialize:

Code Snippet
  1. SharedResourceDictionary<int, string> dictTest =
  2.     new SharedResourceDictionary<int, string>();

To serialize it to Xml we do this:

Code Snippet
  1. XmlWriterSettings settings = new XmlWriterSettings();
  2. settings.Indent = true;
  3.  
  4. using (XmlWriter writer =
  5.     XmlWriter.Create("out.xml", settings))
  6. {
  7.     IntermediateSerializer.Serialize(
  8.         writer,
  9.         dictTest,
  10.         null);
  11. }

To deserialize from Xml we do this:

Code Snippet
  1. XmlReaderSettings settings = new XmlReaderSettings();
  2. using (XmlReader reader =
  3.     XmlReader.Create("out.xml", settings))
  4. {
  5.     this.dictTest = IntermediateSerializer.
  6.         Deserialize<SharedResourceDictionary<int,string>>
  7.         (reader, null);
  8. }

 

Notes

Special thanks to r2d2rigo for helping me hunt down some bugs in the code.

1 comment:

  1. Hey man,

    I know it's been like 2 years since you wrote that but I just got to this problem and your post helped me hunt down my own bugs in my implementation!

    Thanks! :)

    ReplyDelete