3 回答
TA贡献1775条经验 获得超11个赞
异常仅在等待任务时传播
您不能在不等待任务的情况下处理异常。异常仅在线程/任务内传播。因此,如果您不等待,异常只会停止任务。如果在您等待之前抛出异常,它将在您实际等待时传播。
之前做所有的验证,然后做异步工作。
所以,我建议你之前验证:
ValidateId(id); // This will throw synchronously.
Task<Customer> customer = FetchCustomerAsync(id).ConfigureAwait(false);
DoSomethingElse();
return await customer.Name;
这是实现您想要的并行性的最佳方式。
TA贡献1810条经验 获得超4个赞
您是对的,该线程执行异步函数直到它看到等待。事实上,你ArgumentOutofRangeException是由你调用的线程抛出的FetchCustmerNameAsync。即使它是同一个线程也不会得到异常的原因是因为当您await在函数内部使用时,AsyncStateMachine构建了 a 。它将所有代码转换为状态机,但重要的部分是它如何处理异常。看一看:
这段代码:
public void M() {
var t = DoWork(1);
}
public async Task DoWork(int amount)
{
if(amount == 1)
throw new ArgumentException();
await Task.Delay(1);
}
转换为(我跳过了不重要的部分):
private void MoveNext()
{
int num = <>1__state;
try
{
TaskAwaiter awaiter;
if (num != 0)
{
if (amount == 1)
{
throw new ArgumentException();
}
awaiter = Task.Delay(1).GetAwaiter();
if (!awaiter.IsCompleted)
{
// Unimportant
}
}
else
{
// Unimportant
}
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception); // Add exception to the task.
return;
}
<>1__state = -2;
<>t__builder.SetResult();
}
如果你跟着<>t__builder.SetException(exception);( AsyncMethodBuilder.SetException),你会发现它最终会调用task.TrySetException(exception);which 将异常添加到任务的 中exceptionHolder,可以通过Task.Exception属性检索。
TA贡献1111条经验 获得超0个赞
一个简化的 MCVE :
static async Task Main(string[] args)
{
try
{
// enable 1 of these calls
var task = DoSomethingAsync();
// var task = DoSomethingTask();
Console.WriteLine("Still Ok");
await task;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static async Task DoSomethingAsync()
{
throw new NotImplementedException();
}
private static Task DoSomethingTask()
{
throw new NotImplementedException();
return Task.CompletedTask;
}
当您调用 DoSomethingAsync 时,您将看到“Still Ok”消息。
当您调用 DoSomethingTask 时,您将获得您期望的行为:WriteLine 之前的立即异常。
- 3 回答
- 0 关注
- 384 浏览
添加回答
举报