Welcome to MSDN Blogs Sign in | Join | Help

Customizing IntermediateSerializer, part 2

What can you do when serialization helper properties just aren't enough?

Bring out the big guns and write your own ContentTypeSerializer.

If you have ever written a ContentTypeWriter or ContentTypeReader, this should seem familiar. To customize the XML serialization for this test class:

    class TestClass
    {
        public int elf = 23;
    }

We create this helper:

    [ContentTypeSerializer]
    class TestClassSerializer : ContentTypeSerializer<TestClass>
    {
        protected override void Serialize(IntermediateWriter output, TestClass value, ContentSerializerAttribute format)
        {
            int hundreds = value.elf / 100;
            int tens = (value.elf / 10) % 10;
            int ones = value.elf % 10;

            output.Xml.WriteStartElement("elf");
            output.Xml.WriteString(string.Format("{0} hundreds, {1} tens, and {2} ones", hundreds, tens, ones));
            output.Xml.WriteEndElement();
        }

        protected override TestClass Deserialize(IntermediateReader input, ContentSerializerAttribute format, TestClass existingInstance)
        {
            // TODO: this part left as an exercise for the reader :-)

            return new TestClass();
        }
    }

Whenever IntermediateSerializer encounters a TestClass instance, it will now call TestClassSerializer.Serialize, producing this XML:

    <XnaContent>
      <Asset Type="TestClass">
        <elf>0 hundreds, 2 tens, and 3 ones</elf>
      </Asset>
    </XnaContent>

Neat, huh? ContentTypeSerializer gives direct access to the XmlWriter and XmlReader, and thus total flexibility to do absolutely anything you can imagine.

Best of all, I didn't have to change my TestClass to do this. That means games can have a data class shared between their content build and game code, plus a custom ContentTypeSerializer which is only referenced by the Content Pipeline build, so the custom serialization code does not have to be shipped as part of the final game.

Note, however, that writing XML serialization entirely by hand is hard work. This is not something you want to do any more than you absolutely have to!

Note 2: there is a bug in Game Studio versions 2.0 and prior, which means the custom ContentTypeSerializer will be ignored if you call IntermediateSerializer directly from a program of your own. This will only work if IntermediateSerializer is called inside the Content Pipeline build process, from an importer or processor. This is fixed in the 3.0 framework.

Published Tuesday, August 26, 2008 6:57 PM by ShawnHargreaves

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

Wednesday, August 27, 2008 9:30 AM by Giniedp

# re: Customizing IntermediateSerializer, part 2

whew, this is really a good thing.Yesterday i was in the need to have something like a dynamic/flexible serializer, and searched for access to the intermidate reader and writer to allow different versions of a serializable class like

if this is version 1

   do this;

else

   do that

Never thought about writing an own ContentTypeSerializer. Thx for that articles.

Now i need to be able to call the IntermidateSerializer directly :[

Anyway, is that what i need (classes with versions) something you would solve with the intermidate serializer? or does there any other pattern exist for my case. I`m writing a little editor. And as i know, there will be little changes in future. I would like to support older versions of data.

Very great blog. We all learn a lot here.

Wednesday, August 27, 2008 11:41 AM by Ultrahead

# re: Customizing IntermediateSerializer, part 2

"This is fixed in the 3.0 framework."

Good news for my custom level editor.

Wednesday, August 27, 2008 2:58 PM by ShawnHargreaves

# re: Customizing IntermediateSerializer, part 2

> Anyway, is that what i need (classes with versions) something you would solve with the intermidate serializer? or does there any other pattern exist for my case.

For the most advanced and flexible versioning options, a custom ContentTypeSerializer could indeed be a good way to go.

For many simpler things (where an option might be deprecated, or a newer field might not be present in older files) you can do this just by specifying the Optional flag with a ContentSerializerAttribute. We used that for instance in the SpriteFontDescription type, when we added kerning support in the 2.0 framework, but still wanted to be able to deserialize older .spritefont files that did not include this information.

Another option would be to use polymorphism, and keep all the different versions of your data layout around as separate classes (all derived from a common base type). Then your XML could specify eg. a Type="MyDataV2" attribute to indicate which specific type it was using.

Wednesday, August 27, 2008 3:01 PM by Ultrahead

# re: Customizing IntermediateSerializer, part 2

"Then your XML could specify eg. a Type="MyDataV2" attribute to indicate which specific type it was using."

Or Version="1.0.1" ...

Leave a Comment

(required) 
required 
(required) 
 
Page view tracker