我有一个异步方法返回没有数据:

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请求调用中等待任务完成后才响应请求,因此毫无理由地增加响应时间。


当前回答

这不是最好的做法,你应该尽量避免这种情况。

然而,为了解决“在c#中不使用await调用异步方法”的问题,你可以在Task.Run中执行异步方法。该方法将等待MyAsyncMethod完成。

public string GetStringData()
{
    Task.Run(()=> MyAsyncMethod()).Result;
    return "hello world";
}

await异步地打开任务的结果,而仅仅使用Result会阻塞直到任务完成。

如果你想把它包装在一个helper类中:

public static class AsyncHelper
{
    public static void Sync(Func<Task> func) => Task.Run(func).ConfigureAwait(false);

    public static T Sync<T>(Func<Task<T>> func) => Task.Run(func).Result;

}

然后说

public string GetStringData()
{
    AsyncHelper.Sync(() => MyAsyncMethod());
    return "hello world";
}

其他回答

我来晚了,但有一个很棒的库,我一直在使用,我没有看到在其他答案中引用

https://github.com/brminnick/AsyncAwaitBestPractices

如果需要“Fire And Forget”,则调用任务上的扩展方法。

将onException动作传递给调用可以确保两全其——不需要等待执行并降低用户速度,同时保留以优雅的方式处理异常的能力。

在你的例子中,你可以这样使用它:

   public string GetStringData()
    {
        MyAsyncMethod().SafeFireAndForget(onException: (exception) =>
                    {
                      //DO STUFF WITH THE EXCEPTION                    
                    }); 
        return "hello world";
    }

它还提供了可等待的AsyncCommands实现ICommand开箱即用,这是伟大的我的MVVM Xamarin解决方案

在带有消息循环的技术(不确定ASP是否是其中之一)上,您可以阻塞循环并处理消息,直到任务结束,并使用ContinueWith来解除阻塞代码:

public void WaitForTask(Task task)
{
    DispatcherFrame frame = new DispatcherFrame();
    task.ContinueWith(t => frame.Continue = false));
    Dispatcher.PushFrame(frame);
}

这种方法类似于在ShowDialog上阻塞并且仍然保持UI的响应性。

这叫做“开火后忘记”,它还有一个延伸。

消耗一个任务,但不对它做任何事情。在异步方法中用于对异步方法的“触发-忘记”调用。

安装nuget包。

Use:

MyAsyncMethod().Forget();

编辑:最近我还用了另一种方法:

_ = MyAsyncMethod();

这不是最好的做法,你应该尽量避免这种情况。

然而,为了解决“在c#中不使用await调用异步方法”的问题,你可以在Task.Run中执行异步方法。该方法将等待MyAsyncMethod完成。

public string GetStringData()
{
    Task.Run(()=> MyAsyncMethod()).Result;
    return "hello world";
}

await异步地打开任务的结果,而仅仅使用Result会阻塞直到任务完成。

如果你想把它包装在一个helper类中:

public static class AsyncHelper
{
    public static void Sync(Func<Task> func) => Task.Run(func).ConfigureAwait(false);

    public static T Sync<T>(Func<Task<T>> func) => Task.Run(func).Result;

}

然后说

public string GetStringData()
{
    AsyncHelper.Sync(() => MyAsyncMethod());
    return "hello world";
}

我想问题来了,你为什么要这么做?在c# 5.0中使用异步的原因是您可以等待结果。这个方法实际上不是异步的,只是一次调用,这样就不会过多地干扰当前线程。

也许最好是开始一个线程,让它自己完成。