我知道这个问题已被问过好几次了,但是,我正在略微考虑一个不同的变体。
public async Task<string> SomeAsyncMethod(string url)
{
// do some URL validation
if (!valid)
{
throw new Exception("some error");
}
// do async stuff now
return await GetFromUrl(url)
}
// now in caller
public async Task<string> SomeOtherAsyncMethod(string input)
{
var task = SomeAsyncMethod(input);
// there is potential chance that a validation fails and
//exception is thrown even before entering async parts of the called function
// do some independent stuff here
try
{
await task;
}
catch(Exception e)
{
// log error
}
// is the following code correct way to handle exceptions?
if (!task.IsFaulted)
{
return task.Result;
}
// log error from task.Exception
return null;
}
在上面的代码中,可能会发生验证失败,甚至在控件进入方法的异步部分之前抛出异常。我们是否需要围绕try..catch块包装第一个调用?我的实验表明这没用。而是将任务状态设置为Faulted。因此,我认为检查任务状态并相应地返回数据是正确的。 C#专业人士可以对此发表评论吗?
答案 0 :(得分:3)
正如您已经说过的,当您使用async
方法抛出异常时,调用该方法将永远不会抛出,而返回的任务将会出现故障。即使在第一个await
之前抛出异常,也是如此。如果这是您想要的功能,那么您已经拥有它,并且无需进行任何更改。
答案 1 :(得分:3)
我们是否需要围绕try..catch块包装第一个调用?
您可能希望这样做,作为防御性编码措施。 async
方法中的“前置条件”异常遇到与枚举器块相同的问题。在async
情况下,前提条件异常用于故障任务,而不是直接引发。这就是我如何预处理异常。
然而,还有另一种选择。实现可能“急切地”执行前提条件检查,并仅使用故障任务来表示异步异常。即:
public Task<string> SomeMethodAsync(string url)
{
// do some URL validation
if (!valid)
{
throw new Exception("some error");
}
// do async stuff now
return SomeMethodImplAsync(url);
}
private async Task<string> SomeMethodImplAsync(string url)
{
return await GetFromUrl(url)
}
我自己不这样做,但这种做法确实有它的支持者。最值得注意的是,Jon Skeet。
考虑到这一点,除非文档明确指出将在返回的任务上放置前置条件异常,否则您可能应该在SomeMethdAsync
块中包含对try
的调用。