只读局部变量不能用作赋值目标

时间:2012-06-28 19:48:51

标签: c#

如果我有:

var myObjects = new ConcurrentBag<object>();

尝试通过以下方式删除对象:

foreach (var myObject in myObjects.ToArray())
{
    myObjects.TryTake(out myObject);
}

编译器抱怨:&#34; Readonly局部变量不能用作分配目标&#34;

然而,如果我在foreach中添加一个本地引用,它会编译:

foreach (var myObject in myObjects.ToArray())
{
    var localReference = myObject;
    myObjects.TryTake(out localReference);
}

这到底发生了什么?

2 个答案:

答案 0 :(得分:16)

foreach(即myObject中的迭代变量无法foreach内分配新值。这是不允许的。

在第一个场景中,out尝试执行此操作。在第二种情况下,您*永远不会尝试重新分配给myObject,所以没关系。

引用ECMA规范15.8.4,强调我的:

  
      
  1. foreach语句的类型和标识符声明了   声明的迭代变量。

  2.   
  3. 迭代变量对应于只读本地   变量,其范围扩展到嵌入语句。

  4.   
  5. 在执行foreach语句期间,迭代变量   表示迭代所针对的集合元素   目前正在进行中。

  6.   
  7. 如果嵌入语句尝试,则发生编译时错误   修改迭代变量(通过赋值或++和    - 运算符)或将迭代变量作为ref或out参数传递

  8.   

答案 1 :(得分:6)

如果要将检索到的对象分配给数组,请使用for语句,因为您无法为循环变量赋值

object[] arr = myObjects.ToArray();
for (int i = 0; i < arr.Length; i++) {
    myObjects.TryTake(out arr[i]); 
}

现在数组包含检索到的对象,或者在没有对象的情况下为null。


更新

在阅读ConcurrentBag<T>之后,我想我开始明白你的想法了。我上面的第一个解决方案遇到了多线程场景中的竞争条件(使用ConcurrentBag<T>的唯一和唯一的共振)。试试这个

var removedObjects = new List<object>();
object obj;
while (myObjects.TryTake(out obj)) {
    removedObjects.Add(obj);
}

注意:将数据包的对象分配给数组然后循环遍历它并不是一个好主意,因为其他线程可能同时添加或删除了对象。因此,您必须使用这种直接方法。


如果您只想删除对象而不同时检索它们:

object obj;
while (myObjects.TryTake(out obj)) {
}