Are you writing your own XML importer/exporter, or using the built-in IntermediateSerializer? If you're writing your own, then you have the answer to your own question since you're the one implementing it.
Otherwise, I believe that the built-in IntermediateSerializer just knows to treat deserialized collections as collections and assumes that the named members of your top level objects that contain these collections are able to accept these objects as collection items, otherwise it'll bork. It'd be a pretty lame serializer if you couldn't instantiate subclasses to stick in a base class collection from XML.
I say "believe" because I haven't tried to examine the IL or anything like that. Just going based on my own futzing with it.
I put my first whack at a component system on github just recently, and this is what IntermediateSerializer (should be XNA 4, if not it's 3.1 and 4 likely exports similar data):
https://github.com/michaelbartnett/DaHooch_XnaComponentArchTest/blob/master/Project%20Da%20Hooch/xmlTest.xml
Here's a snippet:
<Level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Entities>
<Entity>
<Enabled>true</Enabled>
<UpdateOrder>0</UpdateOrder>
<Name>PLATFORM1</Name>
<Aspects>
<Aspect xsi:type="RenderingAspect">
<Name>renderer</Name>
<DrawOrder>0</DrawOrder>
<Visible>true</Visible>
<CoordinateType>World</CoordinateType>
</Aspect>
<Aspect xsi:type="SpriteAspect">
<Name>sprite</Name>
<Scale>
<X>1</X>
<Y>1</Y>
</Scale>
<LayerDepth>0.2</LayerDepth>
<ImageFile>Sprites/platform</ImageFile>
<OrientationAspect>collider</OrientationAspect>
<CoordinateType>World</CoordinateType>
<DrawOrigin>
<X>256</X>
<Y>32</Y>
</DrawOrigin>
<Tint>
<R>255</R>
<G>255</G>
<B>255</B>
<A>255</A>
<PackedValue>4294967295</PackedValue>
</Tint>
<FlipEffects>None</FlipEffects>
<ImageFrame>
<X>0</X>
<Y>0</Y>
<Width>512</Width>
<Height>64</Height>
<Location>
<X>0</X>
<Y>0</Y>
</Location>
</ImageFrame>
</Aspect>
<Aspect xsi:type="BoxCollisionAspect">
<Name>collider</Name>
<Position>
<X>300</X>
<Y>350</Y>
</Position>
<Rotation>0</Rotation>
<Dimensions>
<X>256</X>
<Y>32</Y>
<Width>512</Width>
<Height>64</Height>
<Location>
<X>256</X>
<Y>32</Y>
</Location>
</Dimensions>
<Mass>100</Mass>
<IsStatic>true</IsStatic>
<CollisionGroup>0</CollisionGroup>
<Enabled>false</Enabled>
<UpdateOrder>0</UpdateOrder>
</Aspect>
</Aspects>
<IsTemplate>false</IsTemplate>
</Entity>
</Entities
</Level>
You'll notice that IntermediateSerializer doesn't even bother specifying the type of <Entities>
or <Aspects>
, presumably the Content XML importer knows what to do when it sees a collection.
This is an XML file I generated using the IntermediateSerializer documented on Shawn Hargreaves' blog. The solution is split up into the Content project, and Engine project, a Game project and one Editor project. The only difference between Editor and Game is some #ifdefs that determine whether to export the current state of the scene as as an XML file, or to load an XML file from the Content project so I could see exactly how it was getting serialized and deserialized.
Here's the stripped down game class to illustrate what I'm talking about:
class Game1 : Microsoft.Xna.Framework.Game
{
private Level level; // Level class contains Entities, which are built out of Aspects (component system)
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
#if EDITOR
FirstLevel.LoadFirstLevel(level, this); // Static class method that instantiates game objects
#else
level = Content.Load<Level>("xnaXmlTest2");
#endif
level.Load(this);
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
currentGameTime = gameTime;
var keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Escape))
{
#if EDITOR
if (levelMode == SAVE_MODE)
{
Entity player = Entity.GetEntityByID(FirstLevel.PlayerID);
string filePath = Content.RootDirectory + @"\..\..\..\..\Content\xnaXmlTest2.xml";
FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite);
IntermediateSerializer.Serialize<Level>(XmlWriter.Create(file), level, filePath);
}
#endif
this.Exit();
}
level.Update(gameTime);
base.Update(gameTime);
}
}
Item
should beMySubClass0
and the second instance ofItem
beMySubClass1
? Is this an arbitrary designation, something where you just know that this is the way things are? Or is it some property in the XML file? Because it really should be the latter. \$\endgroup\$