我有一个异步方法返回没有数据:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
我从另一个返回一些数据的方法调用这个:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
在visual studio中调用MyAsyncMethod()而不等待它会导致“因为此调用未被等待,当前方法在调用完成之前继续运行”警告。在警告页面上,它写道:
只有在确定不希望等待异步调用完成并且被调用的方法不会引发任何异常时,才应该考虑取消警告。
我确定我不想等待调用完成;我不需要,也没有时间。但这种呼吁可能会引发例外。
我遇到过几次这个问题,我相信这是一个普遍的问题,必须有一个共同的解决方案。
我如何安全地调用异步方法而不等待结果?
更新:
对于那些建议我只是等待结果的人,这是对我们的web服务(ASP。NET Web API)。在UI上下文中等待保持UI线程空闲,但在web请求调用中等待任务完成后才响应请求,因此毫无理由地增加响应时间。
如果你想“异步”地获取异常,你可以这样做:
MyAsyncMethod().
ContinueWith(t => Console.WriteLine(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
这将允许您处理“主线程”以外的线程上的异常。这意味着你不必“等待”从调用MyAsyncMethod的线程调用MyAsyncMethod();但是,仍然允许您在异常情况下执行某些操作——但仅在发生异常时才可以。
更新:
从技术上讲,你可以用await做类似的事情:
try
{
await MyAsyncMethod().ConfigureAwait(false);
}
catch (Exception ex)
{
Trace.WriteLine(ex);
}
...如果你需要特别使用try/catch(或using),这将是有用的,但我发现ContinueWith更明确一点,因为你必须知道ConfigureAwait(false)的意思。
Peter Ritchie的答案就是我想要的,还有Stephen Cleary关于ASP早期回归的文章。NET非常有用。
然而,作为一个更普遍的问题(不特定于ASP。NET上下文)下面的控制台应用程序使用Task.ContinueWith(…)演示了Peter的答案的用法和行为
static void Main(string[] args)
{
try
{
// output "hello world" as method returns early
Console.WriteLine(GetStringData());
}
catch
{
// Exception is NOT caught here
}
Console.ReadLine();
}
public static string GetStringData()
{
MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
return "hello world";
}
public static async Task MyAsyncMethod()
{
await Task.Run(() => { throw new Exception("thrown on background thread"); });
}
public static void OnMyAsyncMethodFailed(Task task)
{
Exception ex = task.Exception;
// Deal with exceptions here however you want
}
GetStringData()在不等待MyAsyncMethod()的情况下提前返回,在MyAsyncMethod()中抛出的异常在OnMyAsyncMethodFailed(Task任务)中处理,而不是在GetStringData()周围的try/catch中处理
也许我太天真了,但是,你不能创建一个事件,当GetStringData()被调用时引发,并附加一个EventHandler,调用和等待异步方法?
喜欢的东西:
public event EventHandler FireAsync;
public string GetStringData()
{
FireAsync?.Invoke(this, EventArgs.Empty);
return "hello world";
}
public async void HandleFireAsync(object sender, EventArgs e)
{
await MyAsyncMethod();
}
在代码的某处附加和分离事件:
FireAsync += HandleFireAsync;
(...)
FireAsync -= HandleFireAsync;
不确定这是否可能是反模式(如果是,请让我知道),但它捕获异常并从GetStringData()快速返回。