This project is read-only.

Problem: Collection was modified; enumeration operation may not execute.

Jul 2, 2009 at 3:49 AM

I have started a new development project in XNA with the explicit purpose of making it primarily available in silverlight. Because of this I have two solutions, the primary solution is my XNA solution that references the XNA Framework. The secondary solution references the SilverArcade binaries and all of my source files are added "as link".

As I add new features to the XNA solution I open the SilverArcade solution and run it to make sure everything still works.


There is now something that I have changed that works fine in the XNA solution that doesn't work in the SilverArcade solution and it's not readily obvious why although I have a suspicion.


What I have done is implemented a way for a DrawableGameComponent to signal to the Game that the DrawableGameComponent is closing. It does this through an event that the Game subscribes to when it adds the drawable game component to the the Components list. When the event is triggered, the Game class clears the Component list, then determines which DrawableGameComponent to show next and adds that new component to the Components list. When I do this I get the following error in the SilverArcade solution "Collection was modified; enumeration operation may not execute.". The error is in the Game class. Here is the code snippet where the error is ocurring. It is occurring on the line "base.Update(gameTime);" and there is no inner exception. Any help would be much appreciated.

/// <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)
{
    // Allows the game to exit
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();

    // TODO: Add your update logic here

    base.Update(gameTime);
}

Jul 3, 2009 at 12:24 AM
Edited Jul 3, 2009 at 12:27 AM

In referencing the SilverSprite code instead of the binaries I found that it broke on the following code:

 

public void Update(GameTime gameTime)
{
    foreach (GameComponent gc in _components)
    {
        if (gc.Enabled)
        {
            gc.Update(gameTime);
        }            
    }
    
    Refresh();
}

 

If I replace the foreach with a standard for loop like this:

 

public void Update(GameTime gameTime)
{
    for (int i = 0; i < _components.Count; i++)
    {
        if (_components[i].Enabled)
        {
            _components[i].Update(gameTime);
        }
    }

    Refresh();
}

The error goes away. Is this something we want to change in the Silversprite code to avoid this error?

If so we may want to change it on some other methods as well suchas the Draw method. If someone will let me know I can make the change in the source (assuming gaining access is pretty straight forward).

 

Jul 5, 2009 at 5:30 PM

Thanks I'll take a look at this. The real fix for this would be to apply any changes to the game component collection after the update loop finishes. Changing the loop to a for loop just masks the problem and could have some unpredictable results.

Jul 6, 2009 at 12:55 AM
Edited Jul 6, 2009 at 1:05 AM

I agree

Thanks and please let me know if / when this is fixed. When I go into production I would rather not be using a modified copy of Silversprite since it will prevent me from quickly and easily supporting the latest version.

P.S.

I noticed another problem as well that was causing an error for me. This one is in the SilverArcade.SilverSprite.GameComponentCollection class. Currently in SilverSprite a GameComponent added to the Components collection only has it's Initialize() method called when the Game's Initialize() method is called. Of course a GameComponent needs to be initialized when it is added to the Components collection. Here is the before and after code snippet. The after snippet fixed the error I was getting.

Before

public void Add(GameComponent item)
{
    _components.Add(item);
    item.UpdateOrderChanged += item_Updated;

    DrawableGameComponent dgc = item as DrawableGameComponent;

    if (dgc != null)
    {
        dgc.DrawOrderChanged += item_Updated;
        _drawableComponents.Add(dgc);
    }

    _updateSortOrder = true;
    Refresh();
}

After

public void Add(GameComponent item)
{
    _components.Add(item);
    item.UpdateOrderChanged += item_Updated;

    DrawableGameComponent dgc = item as DrawableGameComponent;

    if (dgc != null)
    {
        dgc.DrawOrderChanged += item_Updated;
        _drawableComponents.Add(dgc);
    }

    // game components are initialized when they
    // are added, not just when the game starts
    item.Initialize();

    _updateSortOrder = true;
    Refresh();
}
Thanks!

Jul 11, 2009 at 3:02 AM

I've checked in something to try to fix this, please try the latest from source control and confirm.

 

Thanks,

Bill

Jul 13, 2009 at 2:30 AM

Both of the above bugs seem to be fixed! Thanks for your help. Is this an approved method for bringing issues to your attention or would you rather we use the Issue Tracker? Would something like this have been resolved so promptly if submitted through that channel?

Thanks

Jul 13, 2009 at 5:59 PM

Glad to hear that it's working for you now. I'd say in the future that the discussion board is better since then others can more easily see what issues people are running into and there can be more of a dialog about it. If something needs to be entered as an issue based on one of these discussions I'll enter it.

Thanks,
Bill