Почему небезопасно выполнять await
внутри .ForEach()
?
В проекте. Net Core 3.1 Я выбираю из некоторого WebApi, список пользователей, соответствующих критериям, затем я удаляю их и, наконец, снова прошу список пользователей. Естественно, на этот раз я ожидаю, что список будет пустым.
ошибочный код
var existing = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
existing.ForEach(async x => await client.DeleteByIdAsync(x.Id));
var ensure = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
ensure.Count.Should().Be(0); <-- ERROR WAS 1!
Я обнаружил, что когда я вставляю Thread.Sleep(50)
перед var ensure
код работает. Это ясно указывает на то, что возникают проблемы с потоками, которых я не понимаю.
рабочий код (с задержкой)
var existing = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
existing.ForEach(async x => await client.DeleteByIdAsync(x.Id));
Thread.Sleep(50);
var ensure = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
ensure.Count.Should().Be(0);
Альтернатива Рабочий код (с использованием foreach)
var existing = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
foreach (var x in existing)
{
await client.DeleteByIdAsync(x.Id);
}
var ensure = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList();
ensure.Count.Should().Be(0);
декомпиляция .ForEach()
Я не вижу, где возникает проблема потоковой передачи
public void ForEach(Action<T> action)
{
if (action == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action);
}
int version = _version;
for (int i = 0; i < _size; i++)
{
if (version != _version)
{
break;
}
action!(_items[i]);
}
if (version != _version)
ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
}