目前,我正在编写一个定期消耗单件集合的应用程序:
lock (_lockItemsReceivedObject)
{
DateTime commitTime = DateTime.Now;
while (ItemsReceivedInstance.Count > 0)
{
ProcessInfo(commitTime);
}
}
这是ProcessInfo:
private void ProcessInfo(DateTime commitTime)
{
Dictionary<Int32, Item>.Enumerator enumerator =
ItemsReceivedInstance.GetEnumerator();
if (enumerator.MoveNext())
{
Item item = enumerator.Current.Value;
// put item into persistent storage and perform other processing...
ItemsReceivedInstance.Remove(enumerator.Current.Key);
}
}
以下是有关例外的更多详细信息:
Error: Collection was modified; enumeration operation may not execute. at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
在程序的其他位置,其他线程正在接收项目并将它们放入单例ItemsReceivedInstance集合中。然而,对我来说没有意义的是,因为我使用了一个锁,所以ItemsReceivedInstance集合不应该被修改,直到它被清空,因为进程退出临界区,为什么我收到这个例外?有没有人有什么建议? TIA。
更新
感谢CodeWeed和Wayne的评论。这是修改集合的可接受方式吗?
{
ConcurrentDictionary<Int32, Item>.Enumerator enumerator =
ItemsReceivedInstance.GetEnumerator();
if (enumerator.MoveNext())
{
Item item = enumerator.Current.Value;
// put item into persistent storage and perform other processing...
var itemToRemove = enumerator.Current.Key;
enumerator.Dispose();
ItemsReceivedInstance.Remove(itemToRemove);
}
}
更新2:
感谢CodeWeed和Wayne以及其他所有考虑过此问题的人。 foreach循环枚举器允许脏读,所以要拍摄我使用ToArray()的字典的快照(参见http://geekswithblogs.net/BlackRabbitCoder/archive/2011/02/17/c.net-little-wonders-the-concurrentdictionary.aspx),这就是我修改代码的方法:
DateTime commitTime = DateTime.Now;
foreach (KeyValuePair<Int32, Item> kvp in ItemsReceivedInstance.ToArray())
{
ProcessInfo(commitTime, kvp.Value);
}
...
private static void ProcessInfo(DateTime commitTime, Item item)
{
// put item into persistent storage and perform other processing...
}
答案 0 :(得分:1)
从技术上讲,这可能有用,但我认为它仍然过于做作。为什么不:
DateTime commitTime = DateTime.Now;
foreach (var kvp in ItemsReceivedInstance)
{
ProcessInfo(commitTime, kvp);
}
ItemsReceivedInstance.Clear();
...
private static void ProcessInfo(DateTime commitTime, KeyValuePair<int, Item> kvp)
{
// put item into persistent storage and perform other processing...
}
请注意,这与您最初尝试实现的目标之间的细微差别在于ProcessInfo
中的异常情况。如果您正在处理异常并且不希望重新处理字典中的项目,那么您将要跟踪哪些项目已成功处理并从字典中删除这些项目,也许在finally
块中。