异步循环中为空引用,但对象没有空

首先,this SO post无法回答此问题,因为它描述了简单/基本对象引用问题。我遇到的问题与多线程异步处理有关,另一篇文章则没有解决。

我有一个多线程.NET winforms应用程序,我正在这样做:

if ( paramList != null ) {
   lock ( paramList ) {
      foreach ( DictionaryEntry param in paramList ) {
         command.Parameters.AddWithValue(param.Key.ToString(),param.Value);
      }
   }
}

paramListOrderedDictionary

我偶尔在foreach行中收到此错误:

  

对象引用未设置为对象的实例。

异步循环中为空引用,但对象没有空

如您所见,param.Key为空,param.Value为空。但这没有任何意义,因为paramList中没有空值,如您所见:

异步循环中为空引用,但对象没有空

在屏幕快照中,您只能看到索引2,但是我也检查了索引0和1,同样的东西,有效数据,没有null。

我对多线程应用程序没有经验,但是由于this SO post中的响应,我将该块放在lock()中。在放入lock()之前,我偶尔会收到错误Collection was modified; enumeration operation may not execute.。在放入锁之后,该错误消失了,但是现在我得到了上面所示的对象引用。

该怎么办?

编辑

根据一些海报的建议,我这样做了:

private static object syncLock = new object();

然后降低用法:

lock ( syncLock ) {
   if ( paramList != null ) {
       foreach ( DictionaryEntry param in paramList ) {
          command.Parameters.AddWithValue(param.Key.ToString(),param.Value);
       }
   }
}

这似乎已经解决了对象引用错误(感谢大家),但是现在我偶尔会得到:

  

集合已修改;枚举操作可能无法执行。

因为尝试这种新方法后出现了完全不同的错误,所以我created a new SO question。我不确定这样做是否正确,因为现在看来这些问题是相关的,而我只是看到同一核心问题的不同症状。

如果有人有想法,仍在寻找解决方案。

mefie 回答:异步循环中为空引用,但对象没有空

(首选)更改您的paramList,因此您无需锁定它。

如果您需要共享,则:

  1. 锁定一个不变的对象,例如private readonly object l = new object();private static readonly(如果需要)。
  2. 检查填充paramList的代码是否也已lock
,

您的代码将无效。如果在进行空值检查时它不为空,但是当您进入锁时为空,怎么办?

There is the standing advise to always have a dedicated thing to lock ontoobject _mutex = new object();已成为习惯。

编辑:暗含暗含,但您可能想像Charles建议的那样将其设为只读。

如果锁定变量/字段,则可能会遇到此问题。或将原始物装箱(由于原始物总是放在不同的盒子中,所以三明治不会做任何事情)。或者其他人试图将其锁定在调用堆栈中,从而导致死锁。

示例代码:

//_mutex is private,readonly and exist exclusively for this operation
lock(_mutex){
  //You only do null checks after you got a lock
  if ( paramList != null ){
    foreach ( DictionaryEntry param in paramList ) {
      command.Parameters.AddWithValue(param.Key.ToString(),param.Value);
    }
  }
}

所有其他读取,写入或处理变量paramList的代码,其Dictionary的整体及其字段(包括任何副本*)也都必须位于lock(_mutex)中。因此他们不能互相碰撞。

*原始类型和字符串的副本是例外。内置基元类型是不可变的。也通常不使用参考机制。而且String类也被设为不可变的,以使其能够以这种方式工作

,

这是解决了我所有问题的解决方案:

var connection = getConnectionFromPool(sourceOrDC);

try {
   lock ( connection ) {
      using ( SqlCommand command = new SqlCommand(sql,connection) ) {
         command.CommandType = CommandType.Text;

         if ( paramList != null ) {
            foreach ( DictionaryEntry param in paramList ) {
               command.Parameters.AddWithValue(param.Key.ToString(),param.Value);
            }
         }

         command.CommandTimeout = 0;
         command.ExecuteNonQuery();
      }
   }

   return true;
}

我不得不在lock()中包含更多代码,并锁定连接。

本文链接:https://www.f2er.com/3130831.html

大家都在问