【问题标题】:Why an object is modified when I retrieve it from a container为什么当我从容器中检索对象时会修改它
【发布时间】:2019-10-15 07:21:25
【问题描述】:

当我将列表放入ConcurrentQueue 并稍后检索它时,内容可能会被修改。为什么?

var list = new List<int> { 1 };
var queue = new ConcurrentQueue<List<int>>();
queue.Enqueue(list);  // Put the list in the queue
list.Clear();         // Clear the list
if (queue.TryDequeue(out var originalList))
  Console.WriteLine(originalList.Count);  // output 0: the original list is empty !?

【问题讨论】:

  • 我的问题有什么问题?我没有更多的代码,它不工作。那我还能说什么。
  • 为什么在访问队列之前要加锁?
  • 你可以提供一个可编译的例子。
  • "Count for objects in list = 0" - 在将 reference 排入队列后清除列表。

标签: c# reference containers


【解决方案1】:

当你将列表加入队列时,它是由reference 传递的,它不是列表的副本,而是对对象的引用。

queue.Enqueue(list);  // put a reference of list into queue

然后你清除它。

list.Clear();  // clear list

然后从堆栈中检索对 if 的引用。

if (queue.TryDequeue(out var originalList))

此时,originalListlist 是对同一个对象的引用。 list 已被清除,因此 originalList 为空。

Console.WriteLine(originalList.Count); // Ouput 0

如果您真的想将数据保留在队列中,则必须创建列表的副本。 一种简短(有效)的方法是使用ToList(),但您可以考虑使用others options

var list = new List<int> { 1 };
var queue = new ConcurrentQueue<List<int>>();
queue.Enqueue(list.ToList()); // enqueue a copy
list.Clear();
if (queue.TryDequeue(out var originalList)) // retrieve a ref to the copy of original data
    Console.WriteLine(originalList.Count);  // output 1

个人建议:复制一个列表可能会花费时间,并且不应该在不考虑至少两次的情况下完成。

【讨论】:

    【解决方案2】:

    您必须编写完整的示例代码才能获得更好的响应。但我注意到您的代码中有一个重要错误:

    ConcurrentQueue作为documentation says

    表示线程安全的先进先出 (FIFO) 集合。

    所以,你必须删除你的 lock 电话

    【讨论】:

    • 我这样做的结果是一样的。
    • 虽然在这种情况下你得到了相同的结果,但是你使用了错误的这个类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2013-11-13
    • 2018-07-07
    相关资源
    最近更新 更多