我一直在使用.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的实现发生了变化,现在是方法之一已经过时了,还是我缺少什么?
我还注意到在堆栈跟踪中,异步方法现在不会在调用之间引入任何额外的帧.我假设这只是为了简化读取堆栈跟踪?
最佳答案
what the correct way to throw errors is from an implementer of an interface that expects an asynchronous method but is in fact synchronous.
如您所发现的,您可以直接抛出异常,也可以将异常放在返回的Task上.
请注意,这会在观察到异常的地方发生变化:
var task = obj1.ExecuteAsync();
await task;
如果直接抛出异常,则会在调用ExecuteAsync时抛出异常.如果在返回的任务上放置了异常,则在等待任务时抛出该异常.大多数情况下,在调用方法后立即等待任务,但并非总是如此(例如,在Task.When各种场景中).
使用异步(任务返回)API,返回的任务表示方法的执行.异步实现的API始终在返回的任务上放置任何异常.所以,我想说任务返回API的期望是任务将收到异常.
在boneheaded exceptions的情况下,您可以采用任何一种方式.由于异常表示代码错误,因此引发错误并不重要.例如,LINQ to Objects将始终立即引发骨头异常,而不是在枚举其返回的枚举器时.
但是,对于所有其他类型的异常,它们肯定应该返回返回的Task.就个人而言,我只是将所有异常放在返回的Task上.