Передача аргументов с изменением значений в "Задача - Поведение"?

Сценарий: асинхронная задача в цикле выполняет метод, содержащий аргументы, которые изменяются по мере продолжения программы:

while(this._variable < 100)
{
    this._variable++; 
    var aTask = Task.Factory.StartNew(() =>
    {
        aList.add(this._variable);
        update(this._savePoint);
    });
}

Если цикл работает быстрее, чем выполняются задачи, будет ли список добавлять текущее значение переменной или переменная, сохраненная локально, и исходное добавленное значение?

Ответы

Ответ 1

Закрытие закрывается над переменными, а не значениями. Поэтому приращение _variable может изменить поведение задачи, которая ссылается на него.

Это можно предотвратить, создав локальную копию:

while (this._variable < 100)
{
    this._variable++;
    int local = _variable;
    var aTask = Task.Factory.StartNew(() =>
    {
        aList.add(local);
        update(this._savePoint);
    });
} 

Или вы можете передать значение заданию как состояние:

while (this._variable < 100)
{
    this._variable++;
    var aTask = Task.Factory.StartNew(object state =>
    {
        aList.add((int)state);
        update(this._savePoint);
    }, this._variable);
} 

Они оба работают, копируя значение _variable в новую временную переменную. В первом случае переменная local определяется внутри области цикла, поэтому вы получаете новую для каждой итерации. Во втором случае вы делаете копию значения _variable, когда передаете ее в Задачу как аргумент state. Если _variable были ссылочным типом, эти решения не сработали; вам придется выполнить клонирование.