我一直在使用.NET 4.6.1中的异步调用,我想知道抛出错误的正确方法是来自需要异步方法但实际上是同步的接口的实现者。例如:
public interface ISomeInterface
{
Task ExecuteAsync();
}
public class SomeClass : ISomeInterface
{
public Task ExecuteAsync()
{
return Task.FromException(new Exception());
}
}
我找到了Task.FromException
here。
所以这是.NET 4.6仍然似乎建议包装异常。但是我可以写下面的代码:
public class SomeClass : ISomeInterface
{
public Task ExecuteAsync()
{
throw new Exception();
}
}
当我使用try / catch块调用第二个实现时,客户端捕获了Exception
,我认为这是我们首先使用Task.FromException
的原因,而且它还包含整个调用堆栈到原始异常(而方法一只有一个堆栈跟踪到客户端的等待操作)。那时似乎第二种方法更好,但似乎每个人都使用方法一。由于async
的实施方式发生了变化,现在方法一已过时了,还是我缺少什么?
我还在堆栈跟踪中注意到async
方法现在不会在调用之间引入任何额外的帧。我假设这只是为了简化读取堆栈跟踪?
答案 0 :(得分:1)
抛出错误的正确方法是来自需要异步方法但实际上是同步的接口的实现者。
正如您所发现的,您可以直接抛出异常,也可以将异常放在返回的Task
上。
请注意,这确实会改变观察到异常的位置:
var task = obj1.ExecuteAsync();
await task;
如果直接抛出异常,则会在调用ExecuteAsync
时抛出异常。如果在返回的任务上放置了异常,则在任务await
时抛出该异常。 大多数当时,在调用方法后,任务立即await
,但并非总是如此(例如,在Task.WhenAll
种情况下)。
使用异步(任务返回)API,返回的任务表示方法的执行。 async
- 实现的API始终在返回的任务上放置任何异常。所以,我会说任务返回API的期望是任务将收到异常。
在boneheaded exceptions的情况下,您可以采用相应的方式。由于异常表示代码错误,因此引发错误并不重要。例如,LINQ to Objects将始终立即引发骨头异常,而不是在枚举其返回的枚举器时。
但是,对于所有其他类型的例外,他们肯定会继续返回Task
。就个人而言,我只是将所有例外都放在了返回的Task
。