C# 列表中的线程不安全异步<>;。ForEach()
为什么在C# 列表中的线程不安全异步<>;。ForEach(),c#,linq,async-await,C#,Linq,Async Await,为什么在.ForEach()中执行等待是不安全的 在.NETCore3.1项目中,我从一些WebApi中选择符合条件的用户列表,然后删除它们,最后再次请求用户列表。当然,这次我希望列表是空的 错误的代码 var existing = (await client.GetByMatchAsync(new SearchParameters() {..})).ToList(); existing.ForEach(async x => await client.DeleteById
.ForEach()中执行等待
是不安全的
在.NETCore3.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!
备选工作代码(使用foreach)
反编译.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();
}
public void ForEach(操作)
{
if(action==null)
{
ThrowHelper.ThrowArgumentNullException(argument.action除外);
}
int版本=_版本;
对于(int i=0;i<\u size;i++)
{
如果(版本!=\u版本)
{
打破
}
行动!(_项[i]);
}
如果(版本!=\u版本)
ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
}
列表的ForEach只执行一个操作
,因此每次迭代都不会等待您提供的操作,在调用完成之前可以继续执行
否则,它可能会有一个带有签名的重载
Task ForEach(Func<T, Task> func)
.ForEach()只执行一个操作,而不是Func,因此您永远不会等待它。existing.ForEach
启动一系列任务,而不是等待它们完成,因此它们都会同时运行foreach{await}
在开始下一个任务之前等待上一个任务。在foreach反编译中,action!(_项目[i]);感叹号是一个奇怪的语句吗?@CRice问ReSharper是什么代码>平均值;)这个问题被描述为#5,因为我不确定,我只想问:您仍然对async(value)感到困惑吗=>等待任务。CompletedTask
可以同时分配给Fun
和Action
?@Ackdari我知道它可以这样,但如果在不同的时间进行,则不能将一个实例分配给另一个实例-没有隐式转换。
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();
}
Task ForEach(Func<T, Task> func)
Action<string> a = async (value) => await Task.CompletedTask;
existing.ForEach(async x => await client.DeleteByIdAsync(x.Id));