Сбой Task.Start, когда действия продолжения не являются встроенными

#c# #.net

#c# #.net

Вопрос:

Что не так со следующим кодом? Сбой Task.Start с исключением index out of range. Чтобы быть более понятным .. это сбой, потому что значение i принимает значение 3 в цикле for!!!

 ActionProvider m1 = new ActionProvider();
ActionProvider m2 = new ActionProvider();
ActionProvider m3 = new ActionProvider();

List<Action> actions = new List<Action>() 
{
    ()=> { m2.DoIt(); }, 
    ()=> { m3.DoIt(); }, 
};

Task t = new Task(() => { m1.DoIt(); });

for (int i = 0; i < actions.Count; i  )
{
    t.ContinueWith(t1 => actions[i]());
}

t.Start();
  

Ответ №1:

Вероятно, это потому, что вы повторно используете одну и ту же переменную, i, несколько раз. Итак, при выполнении задачи i был увеличен.

Попробуйте изменить свой цикл for следующим образом:

     for (int i = 0; i < actions.Count; i  )
    {
        var action = actions[i];
        t.ContinueWith(t1 => action());
    }
  

Единственное отличие здесь в том, что я создаю копию переменной, которую я передаю ContinueWith.

Комментарии:

1. Точно — для получения дополнительной информации см. blogs.msdn.com/b/ericlippert/archive/2009/11/12 /…

2. Если я изменяю код для использования для каждого, интересно, что это выполняет код три раза для каждого (var item в actions) { t.ContinueWith(t1 => item()); }

3. @user730702: Все так, как и ожидалось. С помощью foreach переменная item будет обновляться каждый раз, точно так же, как если бы вы делали то, что я предложил в своем ответе. В вашем первом случае вы ссылаетесь на переменную i внутри делегата, который вы вызываете из ContinueWith. Этот делегат затем вызывается позже, после того как я изменил его значение.