我在做一个xna游戏,问题涉及到以下几个类:
游戏类——该类监听下面两个类的事件监听器
Player类——这个类发起一个Fire()事件,告诉游戏玩家发射了一颗子弹
Bullet 类 - 此类启动一个 SelfDestruct() 事件(在一定行进距离后),告诉游戏必须删除该实例
游戏类有一个子弹列表,在更新方法中它在这个列表上做一个 foreach
Fire() 的事件监听器将新项目符号添加到项目符号列表
SelfDestruct() 的事件监听器从列表中删除发件人(通过转换为项目符号)
这两个事件以及更新方法都会锁定列表以确保线程安全。 但它仍然抛出异常,告诉列表在 foreach 期间被修改。
我该如何解决这个问题;因为我确实锁定了列表..但这不起作用:
Update:
public void Update(GameTime gameTime)
{
player.Update(GameTime gameTime);//can throw fire event
lock(Bullets)//Lock the list for thread safett
{
foreach(Bullet b in Bullets)//Throws exception when bullet is added/removed
b.Update(gameTime);//can throw selfdestruct event
}
}
Fire listener:
void listen_fire(object sender, EventArgs e)
{
Player p = (Player)sender;/used to get coordinates and rotation stored in the player
lock(Bullets)
{
Bullets.Add(new Bullet(p.Position,p.Rotation));
}
}
Self destruct listener:
void listen_selfdestruct(object sender, EventArgs e)
{
lock(Bullets)
{
Bullets.Remove((Bullet)sender);
}
}
我认为这个解决方案可能会失败,因为事件是在一个线程中抛出的,该线程本身已经锁定了列表
欢迎任何解决方案,感谢阅读我的问题
最佳答案
foreach 中使用的集合是不可变的。这在很大程度上是设计使然。
正如它在 MSDN 上所说的那样:
The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add or remove items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.
例如这段代码会抛出异常:
List<string> lst = new List<string>();
lst.Add("aaa");
lst.Add("bbb");
foreach (string curr in lst)
{
if (curr.Equals("aaa"))
{
lst.Remove(curr);
}
}
所以我这样做是为了在迭代时不会从列表中删除:
List<string> lst = new List<string>();
lst.Add("aaa");
lst.Add("bbb");
List<string> lstToDel = new List<string>();
foreach (string curr in lst)
{
if (curr.Equals("aaa"))
{
lstToDel.Add(curr);
}
}
foreach (string currToDel in lstToDel)
{
lst.Remove(currToDel);
}
现在我不知道你的 Bullets
中有哪些项目,但你不能在 foreach
语句中更新或删除它们
关于使用 lock() 的 C# 事件监听器仍然抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18555711/