异步方法C#中的异常处理
本文关键字:异常处理 异步方法 | 更新日期: 2023-09-27 18:30:13
我知道这个问题已经被问了好几次了,但是,我看到的是一个稍微不同的变体。
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;
}
在上面的代码中,甚至在控件进入方法的异步部分之前,验证就可能失败并引发异常。我们是否需要将第一次通话也包含在尝试中。。抓块?我的实验表明这是没有用的。相反,任务状态设置为Faulted。因此,我认为检查Task状态并相应地返回数据是正确的。C#专业人士可以对此发表评论吗?
正如您已经说过的,当您有一个抛出异常的async
方法时,调用该方法永远不会抛出,相反,返回的任务只会出错。即使在第一个await
之前抛出异常,也是如此。如果这是您想要的功能,那么您已经拥有了它,无需更改任何内容。
我们是否需要将第一次通话也包含在尝试中。。抓块?
您可能希望这样做,作为一种防御编码措施。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。
考虑到这一点,除非文档明确指定先决条件异常将放置在返回的任务上,否则您可能应该在try
块中包含对SomeMethdAsync
的调用。