Мне кажется, это намеренное решение.
Как вы уже знаете, SetValueInAsyncMethod
компилируется в конечный автомат, который неявно захватывает текущий ExecutionContext. Когда вы изменяете переменную AsyncLocal
, это изменение не возвращается обратно к вызывающей функции. Напротив, SetValueInNonAsyncMethod
не является асинхронным и, следовательно, не компилируется в конечный автомат. Следовательно, ExecutionContext не фиксируется, и любые изменения в AsyncLocal
-переменных видны для вызывающей стороны.
Вы также можете захватить ExecutionContext самостоятельно, если вам это нужно по какой-либо причине:
private static Task SetValueInNonAsyncMethodWithEC()
{
var ec = ExecutionContext.Capture(); // Capture current context into ec
ExecutionContext.Run(ec, _ => // Use ec to run the lambda
{
asyncLocal.Value = 3;
PrintValue();
});
return Task.CompletedTask;
}
Это выдаст значение 3, а Main выдаст 2.
Конечно, проще преобразовать SetValueInNonAsyncMethod
в асинхронный, чтобы компилятор сделал это за вас.
Что касается кода, который использует AsyncLocal
(или CallContext.LogicalGetData
в этом отношении), важно знать, что изменение значения в вызываемом асинхронном методе (или любом захваченном ExecutionContext) не будет «возвращаться». Но вы, конечно, можете по-прежнему обращаться к AsyncLocal
и изменять его, если вы не переназначаете его.