2012-03-12 110 views
1

我知道在迭代它时我无法修改集合。InvalidOperationException:已修改集合

通常我会制作我想要迭代的集合的副本,然后迭代副本以避免错误。

我的程序;然而,对我正在尝试制作副本的集合进行了很多快速修改。

错误是否会发生,因为我正在修改父集合时正在创建副本?

我知道ConcurrentDictionary为跨线程提供了某种锁定机制。有没有类似的东西可以用来防止这个错误?

// Original collection: 
    Dictionary<string, Enemy> Dict_Enemies = new Dictionary<string, Enemy>(); 

    // Copy of original collection: (this line throws the exception) 
    Dictionary<string, Enemy> Dict_Enemies_Copy = new Dictionary<string, Enemy>(Dict_Enemies); 
+0

一个[ConcurrentDictionary(http://msdn.microsoft.com/en-us/library/dd287191 .aspx)为'Dict_Enemies'? – 2012-03-12 06:35:57

+0

当我使用ConcurrentDictionary时,我的程序似乎挂在通常会抛出异常的地方。也许我在其他地方有一个问题。 – 2012-03-12 06:47:50

+0

可以使用[ConcurrentDictionary.ToArray()](http://msdn.microsoft.com/zh-cn/library/dd287109.aspx)方法以*线程安全*方式复制它。看看我的答案。 – 2012-03-12 07:23:04

回答

2

尝试使用ConcurrentDictionary代替Dict_Enemies以允许它从多个线程进行修改。然后,使用ToArray()方法做它的一个副本线程安全的操作:为什么不使用

// Original collection: 
var Dict_Enemies = new ConcurrentDictionary<string, Enemy>(); 

// Thread-safe copy: 
ICollection<KeyValuePair<string, Enemy>> Dict_Enemies_Copy = Dict_Enemies.ToArray(); 
+0

请注意,ConcurrentDictionary的处理本身并不重要 - 您必须更改某些代码,因为CD上的某些操作(例如添加)可能因为并发问题而返回“false” - 在这种情况下,您必须重试操作! CD很不错,但是如果你还没有封装你的访问权限,那么就不会有这样的问题 – Carsten 2012-03-12 07:21:42

+0

@CarstenKönig同意。切换到“ConcurrentDictionary”当然需要对项目添加/删除的方式进行一些更改。但是,根据需求,[有多种方式可以解决此问题](http://msdn.microsoft.com/zh-cn/library/dd997369.aspx)。 – 2012-03-12 07:28:16

+0

我认为这解决了我的问题,谢谢。当我从并发字典中移除一个密钥时,我可以使用虚拟对象作为'out'参数吗?虚拟foo; Dict.TryRemove(key,out foo); – 2012-03-12 07:30:30

0

封装这个词典作为一类的私有成员,并使用锁(在两地相同的锁定对象,可能是字典本身),以确保写入和副本不会同时出现时间。不要让任何地方直接访问字典。

0

但类似的代码是perfeclty为我工作.....你能给你更多的解释你的代码?

Dictionary<int, Test> dicOrg = new Dictionary<int, Test>();//Original 
    dicOrg.Add(1, new Test() {id= 1,name="name",add="add"}); 
    Dictionary<int, Test> dicCopy = new Dictionary<int,Test>(dicOrg);//Copy of dicOrg 
+0

我有多种方法可以同时删除项目并向dicOriginal添加项目。 我有各种方法同时拷贝dicOriginal。 我在任何尝试制作dicOriginal副本的地方都会遇到异常情况。 – 2012-03-12 07:02:17

1

一个Dictionary<K,V>不支持多个并发的作家,这意味着你必须已经有一个锁。只要确保您在按住该锁的同时创建副本。

+0

我没有锁定,因为我不确定如何正确实施。如果我使用'lock(dictionary){// dosomething //}',是不是会导致我的程序的其他部分停止正常工作,因为他们将无法访问字典? – 2012-03-12 07:05:58

+0

我需要某种方式来锁定字典,但有其他方法检查锁,等待它被解锁,然后继续。 – 2012-03-12 07:07:42

+0

我试图锁定副本,而我迭代它,但我仍然得到异常... – 2012-03-12 07:15:24

相关问题