【发布时间】:2019-11-09 00:33:13
【问题描述】:
我的 .NET 4.6.2 winforms 应用程序中有以下代码:
paramList 是一个OrderedDictionary。
if ( paramList != null ) {
foreach ( DictionaryEntry param in paramList ) {
command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
}
}
在我开始在应用程序中实现更多异步/多线程处理之前,它总是很有效。现在,当上面的代码运行时,我偶尔会收到以下错误:
System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
我似乎根本没有修改集合,所以我不知道它为什么抱怨。
我了解这些帖子中的讨论/解决方案,但似乎不适用于我的:
Collection was modified exception
System.InvalidOperationException: Collection was modified
使这个线程安全的最好方法是什么?
编辑#1
我现在有这个:
private static object syncLock = new object();
[...]
lock ( syncLock ) {
if ( paramList != null ) {
foreach ( DictionaryEntry param in paramList ) {
command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
}
}
}
我运行了几次,然后问题又出现了:
即使在lock() 内部,这怎么可能仍然发生?我能做什么?
编辑#2
paramList 总是由调用者创建并传递给函数,例如:
var paramList = new OrderedDictionary();
paramList.Add("RuleID", btRule.RuleID);
paramList.Add("TypeSeq", 0);
paramList.Add("Type", btRule.Action);
bool result = await ExecuteQueryAsync(sql, paramList, connection);
public static async Task<bool> ExecuteQueryAsync(string sql, OrderedDictionary paramList, SqlConnection connection) {
try {
using ( SqlCommand command = new SqlCommand(sql, connection) ) {
command.CommandType = CommandType.Text;
lock ( syncLock ) {
if ( paramList != null ) {
foreach ( DictionaryEntry param in paramList ) {
command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
}
}
}
command.CommandTimeout = 0;
await command.ExecuteNonQueryAsync();
}
return true;
}
catch ( Exception ex ) {
[...]
}
}
【问题讨论】:
-
在任何线程上对 paramList 的任何修改都会导致此问题,您很可能在某处遇到线程安全问题
-
你可以尝试locking paramList 在异步方法中访问它的任何地方
-
paramList是什么?它从何而来?它是什么类型的? -
您确实需要向我们提供minimal reproducible example 来诊断此问题。但是,作为临时修复,请尝试在
foreach中的paramList之后添加.ToList(),看看问题(大部分)是否消失。 -
我编辑了问题以给出 paramList (
OrderedDictionary) 的类型,它没有ToList()。
标签: c#