Игнорируйте на мгновение абсурдность await
вызова Enumerable.Range
. Это просто для того, чтобы вызвать крах-поведение. Это так же легко может быть методом, который выполняет некоторые сетевые операции ввода-вывода для создания коллекции объектов значений. (Действительно, именно там я увидел, что произошел сбой.)
Если я прокомментирую строку Interlocked.Exchange
, компилятор не сработает.
public class Launcher
{
private static IEnumerable<int> _foo;
static void Main(string[] args)
{
DoWorkAsync().Wait();
}
private static async Task DoWorkAsync()
{
RefreshCache();
foreach (var element in _foo)
{
Console.WriteLine(element);
}
Console.ReadLine();
}
private static async void RefreshCache()
{
Interlocked.Exchange(ref _foo, await Cache());
}
private static async Task<IEnumerable<int>> Cache()
{
return Enumerable.Range(0, 10);
}
}
Изменение RefreshCache()
на этом не позволяет компилятору сбой:
private static async void RefreshCache()
{
var foo = await Cache();
Interlocked.Exchange(ref _foo, foo);
}
Edit:
Еще более простое, самодостаточное воспроизведение, предоставляемое @Servy
public class Worker
{
private static int foo;
private static async void DoWork()
{
DoNothing(ref foo, await Task.FromResult(0));
}
private static void DoNothing(ref int item, int other)
{
}
}