我的代码将异步方法与异常处理相结合。代码非常简单,所有任务都在等待,并且没有async void
方法:
async Task DoWorkSafelyWithStateMachine()
{
try
{
await DoWorkThatMightThrowException();
}
catch (Exception exception)
{
Console.WriteLine("With state machine: " + exception.Message);
}
}
等待此方法不会引发异常,因为吞下了异常:
await DoWorkSafelyWithStateMachine(); // No exception thrown
但是,代码并不总是捕获异常,因为它应该这样做。当编译方法以稍微不同的方式编写时,编译器不会创建异步状态机,就会出现问题:
Task DoWorkSafelyWithoutStateMachine()
{
try
{
return DoWorkThatMightThrowException();
}
catch (Exception exception)
{
Console.WriteLine("Without state machine: " + exception.Message);
return Task.CompletedTask;
}
}
该方法未使用async
进行修饰,并且在方法中没有等待任何内容。而是由try
内的方法返回的任务返回给调用者。但是,根据我的经验,编译器的神奇之处仍然确保如果try
中的方法抛出异常,它将被异常处理程序捕获。好吧,显然这并非总是如此。
为了测试同一方法的这两个变体,我让DoWorkThatMightThrowException
抛出异常。如果该方法不必在方法体中使用await
,则可以使用或不使用异步状态机来实现:
async Task DoWorkThatMightThrowExceptionWithStateMachine()
{
throw new Exception("With state machine");
await Task.CompletedTask;
}
Task DoWorkThatMightThrowExceptionWithoutStateMachine()
{
throw new Exception("Without state machine");
return Task.CompletedTask;
}
我发现从DoWorkThatMightThrowExceptionWithStateMachine
调用DoWorkSafelyWithoutStateMachine
并没有捕获抛出的异常。其他三种组合确实捕获了异常。特别是,在任何一种方法中都没有涉及异步状态机的版本捕获异常并且我错误地推断了这一观察结果,不幸的结果是我的一些代码现在有微妙的错误。
| Throw + state machine | Throw - state machine | --------------------------+-----------------------+-----------------------+ Try/catch + state machine | Caught | Caught | Try/catch - state machine | Not caught | Caught |
做这个实验我了解到我总是需要在await
块内try
执行任务(表中的第一行)。但是,我不理解表格第二行的不一致性。请解释一下这种行为。它在哪里记录?搜索有关此信息并不容易。异常被丢失的更基本问题"因为不等待任务将主导搜索结果。
答案 0 :(得分:3)
我不明白表格第二行的不一致性
右侧案例(根本没有国家机器)是微不足道的:
try/catch
区块内调用方法catch
黑色抓住它 - 没什么特别的左侧实际上也很容易理解:
try/catch
区块内调用方法Task
,表示在实现方法时执行方法的内容(1) Wait
或await
返回Task
或尝试访问其Result
属性,就不会(重新)抛出异常在try
区块内。 (1)我希望我的英语能更好地找到更好更准确的描述。正如Servy指出的那样,在您的示例中,已返回已故障的Task
。
答案 1 :(得分:3)
当catch
块中抛出异常时,try
块将执行。当您编写return DoWorkThatMightThrowExceptionWithStateMachine();
时,所有try块正在构建标记为出错的Task
并返回它。不会抛出任何异常,因此不会运行catch
块。
如果等待故障任务,它将重新抛出该异常,因此抛出异常。当您调用DoWorkThatMightThrowExceptionWithoutStateMachine
时,方法本身会抛出异常,而不是返回错误的任务,因此try
块中会抛出异常。