Ответ 1
Почему?
Из-за того, как ваш struct
поднимается на конечный автомат.
Вот что выглядит ChangeAsync
:
[DebuggerStepThrough, AsyncStateMachine(typeof(Program.Structure.<ChangeAsync>d__4))]
public Task ChangeAsync(int iValue)
{
Program.Structure.<ChangeAsync>d__4 <ChangeAsync>d__;
<ChangeAsync>d__.<>4__this = this;
<ChangeAsync>d__.iValue = iValue;
<ChangeAsync>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
<ChangeAsync>d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = <ChangeAsync>d__.<>t__builder;
<>t__builder.Start<Program.Structure.<ChangeAsync>d__4>(ref <ChangeAsync>d__);
return <ChangeAsync>d__.<>t__builder.Task;
}
Важная строка такова:
<ChangeAsync>d__.<>4__this = this;
Компилятор снимает копию вашей структуры в свою машину состояния, эффективно обновляя ее копию со значением 45. Когда метод асинхронизации завершен, он перепутал копию, а экземпляр вашего Структура остается неизменной.
Это несколько ожидаемое поведение при работе с изменяемыми структурами. Вот почему они склонны быть злыми.
Как вам обойти это? Поскольку я не вижу изменения этого поведения, вам нужно создать class
вместо struct
.
Edit:
Отправлено это как проблема на GitHub. Получил хорошо образованный ответ от @AlexShvedov, который объясняет немного более глубокую сложность структур и состояний машин:
Так как выполнение каждого замыкания может быть произвольно отложено, нам нужно каким-то образом задерживать жизнь всех участников, захваченных в закрытие. Нет никакого способа сделать это в целом для этого типа значения, так как тип значения может быть выделен в стеке (локальные переменные значения типы) и пространство стека будут повторно использоваться при выводе выполнения метода.
В теории, когда тип значения хранится как поле некоторого управляемого объект/элемент массива, С# может испускать код замыкания для создания структуры мутация в месте. К сожалению, нет никаких сведений о том, где это значение находится при испускании кода элемента структуры, поэтому С# просто заставить пользователей обрабатывать эту ситуацию вручную (путем копирования это значение большую часть времени, как предлагалось сообщение об ошибке).