Почему объект изменяется, когда я получаю его из контейнера - PullRequest
0 голосов
/ 15 октября 2019

Когда я помещаю список в 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 !?

Ответы [ 2 ]

3 голосов
/ 15 октября 2019

Когда вы ставите в очередь список, он передается ссылкой , это не копия списка, а ссылка на объект.

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

Затем вы очищаете его.

list.Clear();  // clear list

Затем вы извлекаете ссылку на if из стека.

if (queue.TryDequeue(out var originalList))

На этом этапе originalList и list являются ссылками на один и тот же объект. list как было очищено, следовательно, originalList пусто.

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

Если вы действительно хотите сохранить данные в очереди, вам нужно создать копию списка. Короткий (и эффективный) способ сделать это - использовать ToList () , но вы можете рассмотреть другие опции .

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

Персональный совет: копированиеСписок может стоить времени и не должен быть составлен, не подумав об этом хотя бы дважды.

0 голосов
/ 15 октября 2019

Вы должны написать полный пример кода, чтобы получить лучший ответ. Но я заметил важную ошибку в вашем коде:

ConcurrentQueue, как сказано в документации :

Представляет потокобезопасный первый-первый-первый-выход(FIFO) коллекция.

Итак, вы должны удалить свои lock звонки

...