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

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


当前回答

我最终得到了这个解决方案:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

public string GetStringData()
{
    // Run async, no warning, exception are catched
    RunAsync(MyAsyncMethod()); 
    return "hello world";
}

private void RunAsync(Task task)
{
    task.ContinueWith(t =>
    {
        ILog log = ServiceLocator.Current.GetInstance<ILog>();
        log.Error("Unexpected Error", t.Exception);

    }, TaskContinuationOptions.OnlyOnFaulted);
}

其他回答

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

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解决方案

我最终得到了这个解决方案:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

public string GetStringData()
{
    // Run async, no warning, exception are catched
    RunAsync(MyAsyncMethod()); 
    return "hello world";
}

private void RunAsync(Task task)
{
    task.ContinueWith(t =>
    {
        ILog log = ServiceLocator.Current.GetInstance<ILog>();
        log.Error("Unexpected Error", t.Exception);

    }, TaskContinuationOptions.OnlyOnFaulted);
}

也许我太天真了,但是,你不能创建一个事件,当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()快速返回。

如果你想“异步”地获取异常,你可以这样做:

  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)的意思。

这很简单,只需调用asyncMethod()。结果呼叫无等待。下面是示例代码,这里是小提琴

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
                    
public class Program
{
    public static void Main()
    {   
        var asyncDemo = new AsyncDemo();
        asyncDemo.TestMethod1Void().Wait();
        var result = asyncDemo.TestMethod1().Result;
        Console.WriteLine(result);
    }
}

public class AsyncDemo {
    
    public async Task<string> TestMethod1()
    {
        Thread.Sleep(1000);
        return  "From Async Method";        
    }
    
    public async Task TestMethod1Void()
    {
        Thread.Sleep(1000);
        Console.WriteLine("Async Void Method");     
    }
}