Насколько я понимаю, их нет. Пожалуйста подтвердите.
Предположим, у меня есть объект Processor, который содержит List‹T›, где T — ссылочный тип.
Поток пользовательского интерфейса создает экземпляр объекта Processor и периодически обращается к нему для получения List‹T›.
Объект-процессор также запускает задачу, имеющую ссылку на List‹T›, когда он создается.
Блокировка используется для резервирования доступа к List‹T› в геттере и в задаче, чтобы гарантировать, что они имеют эксклюзивный доступ к List‹T›.
public class Processor
{
private List<T> _list = new List<T>();
private Object _listLock = new Object();
public Processor()
{
// populate _list
Task t = new Task(Process);
t.Start();
}
public List<T> GetList()
{
lock(_listLock)
{
return _list;
}
}
private void Process()
{
while(!doneProcessing)
{
lock(_listLock)
{
// access and modify _list items
}
Thread.Sleep(...);
}
}
}
Но даже если List‹T› заблокирован в геттере и он вернул ссылку на список без проблем, задача, запущенная процессором, по-прежнему изменяет элементы списка ссылочного типа, когда захватывает блокировку.
Элементы списка по-прежнему могут быть изменены задачей процессора, и доступ к ним в потоке пользовательского интерфейса не будет потокобезопасным.
Если я прав, очевидное решение состоит в том, чтобы геттер возвращал новый список, заполненный глубокими копиями элементов списка.
public List<T> GetList()
{
lock(_listLock)
{
return _list.Select(t => t.Clone()).ToList();
}
}
Что еще можно сделать?
ToList()
создает копию списка. - person stuartd   schedule 24.11.2016List<T>
, которые вы используете, а не весь список. Таким образом, вы можете использовать блокировку доступа и модификации элементов. - person Fredrik Lundvall   schedule 24.11.2016