Во время прогулки по собаке я думал о Action<T>
, Func<T>
, Task<T>
, async/await
(да, тупо, я знаю...) и сконструировал небольшую пробную программу в своем уме и задался вопросом, что ответ был. Я заметил, что не уверен в результатах, поэтому создал два простых теста.
Здесь настройка:
- У меня есть переменная класса (строка) класса.
- Ему присваивается начальное значение.
- Переменная передается как параметр методу класса.
- Метод не будет выполняться напрямую, а вместо него назначен "Действие".
- Перед выполнением действия я изменяю значение переменной.
Каким будет выход? Начальное значение или измененное значение?
Немного удивительно, но понятно, выход - это измененное значение. Мое объяснение: переменная не помещается в стек до тех пор, пока действие не выполнится, поэтому оно будет изменено.
public class foo
{
string token;
public foo ()
{
this.token = "Initial Value";
}
void DoIt(string someString)
{
Console.WriteLine("SomeString is '{0}'", someString);
}
public void Run()
{
Action op = () => DoIt(this.token);
this.token = "Changed value";
// Will output "Changed value".
op();
}
}
Затем я создал вариант:
public class foo
{
string token;
public foo ()
{
this.token = "Initial Value";
}
Task DoIt(string someString)
{
// Delay(0) is just there to try if timing is the issue here - can also try Delay(1000) or whatever.
return Task.Delay(0).ContinueWith(t => Console.WriteLine("SomeString is '{0}'", someString));
}
async Task Execute(Func<Task> op)
{
await op();
}
public async void Run()
{
var op = DoIt(this.token);
this.token = "Changed value";
// The output will be "Initial Value"!
await Execute(() => op);
}
}
Здесь я сделал DoIt()
вернуть a Task
. op
теперь является Task
и уже не является Action
. Метод Execute()
ожидает выполнения задачи. К моему удивлению, выход теперь "Начальное значение".
Почему он ведет себя по-другому?
DoIt()
не будет выполняться до тех пор, пока Execute()
не будет вызван, поэтому почему он фиксирует начальное значение token
?
Полные тесты: https://gist.github.com/Krumelur/c20cb3d3b4c44134311f и https://gist.github.com/Krumelur/3f93afb50b02fba6a7c8