享受生活,享受学习

常用链接

统计

好友类

技术类

最新评论

在Dictionary使用foreach的注意

   最近在对博客园的程序进行性能优化,在优化过程中用到了Dictionary,在通过foreach将Dictionary中的数据写入数据库时,遇到了这样的错误:
     Collection was modified; enumeration operation may not execute.
     
     代码类似这样的:    
Dictionary<intint> _dictionary = new Dictionary<intin>();
//添加数据操作省略
foreach(KeyValuePair<intint> item in _dictionary)
 {
 }

     在执行foreach时,其他线程对_dictionary进行了Add操作,改变了_dictionary中的数据,从而产生了上述的异常信息。

     那什么会产生这样的异常信息呢?
     foreach实际上执行的代码是:    

Dictionary<intint>.Enumerator enumerator = _dictionary.GetEnumerator(); 
try  

   
while (enumerator.MoveNext())  
   { 
     
    } 

finally  

   IDisposable d 
= enumerator as IDisposable; 
   
if (d != null) d.Dispose(); 
}

     通过Reflector查看Dictionary<TKey, TValue>.Enumerator.MoveNext()源代码,我们会发现开始处有这样的代码:
if (this.version != this.dictionary.version)
      {
            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
      }

     而异常就是在这里发生的,因为Add操作时改变了Dictionary的version,通过查看Insert(TKey key, TValue value, bool add)的源代码会看出。
     我觉得Dictionary<TKey, TValue>应该提供一个方法,可以设置在MoveNext时是否进行版本检查,因为有时在foreach操作时,可能并不关心Dictionary中的数据是否被修改,我遇到的就是这样的情况,现在由于这个问题而不能使用foreach,而只能采取其他方法遍历Dictionary<TKey, TValue>中的数据。
     我采用的方法是:

Dictionary<intint> _dictionary = new Dictionary<intin>();
//添加数据操作省略
int[] dataArray = new int[_dictionary.Values.Count];
_ dictionary.Values.CopyTo(evcArray, 
0)
for (int i = 0; i < dataArray.Length; i++)
  {
   }

第2种方法在读取的时候上锁。
  lock(tcClientList.SyncRoot)  
  {  
  foreach   (TcClient   tcClient   in   tcClientList)  
  ...  
  }  

posted on 2007-10-26 17:09 徘徊中的海鸟 阅读(157) 评论(1)  编辑 收藏 所属分类: C#

评论

#1楼  2007-12-26 23:16 xc#      

疑问:
第一种方法加锁不知道有不有用?

第二种方法 _ dictionary.Values.CopyTo(evcArray, 0)一句要不要加锁?
  回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-10-26 18:03 编辑过