如何在C#中安全地调用异步方法而无需使用await

492

我有一个返回无数据的async方法:

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";
}

调用MyAsyncMethod()而不等待它会在Visual Studio中引发"因为此调用没有被等待,所以当前方法在调用完成前继续运行"的警告。在该警告页面上,它指出:
“只有在确信您不想等待异步调用完成且被调用的方法不会引发任何异常时,您才应考虑抑制警告。”
我确定我不需要等待调用完成;我没有时间等待。但是该调用可能会引发异常。
我曾经遇到过这个问题,我相信这是一个常见的问题,必须有一个常见的解决方案。
如何安全地调用异步方法而不等待结果?
更新:
对于建议我只需等待结果的人,这是响应我们Web服务(ASP.NET Web API)上的Web请求的代码。在UI上下文中等待可以保持UI线程空闲,但在Web请求调用中等待Task完成将在响应请求之前等待,从而增加了响应时间,没有理由这样做。

为什么不创建一个完成方法并在那里忽略它呢?因为如果它在后台线程上运行,那么它无论如何都不会阻止程序终止。 - Yahya
2
如果您不想等待结果,唯一的选择是忽略/抑制警告。如果您确实想等待结果/异常,则使用MyAsyncMethod().Wait() - Peter Ritchie
5
关于你的修改:我不理解。假设响应是在请求后1秒钟发送给客户端,而你的异步方法在2秒后抛出异常。你会如何处理这个异常?如果你的响应已经发送给客户端,你不能将异常发送给客户端。那么你还能怎么处理它? - user743382
2
@Romoku 好的,假设有人看日志的话。 :) - user743382
4
一种 ASP.NET Web API 的变体是在一个长时间运行的进程(例如 Windows 服务)中自托管 Web API 场景,其中请求创建一个耗时的后台任务来执行某些昂贵的操作,但仍然希望能够快速收到 HTTP 202(已接受)响应。 - David Rubin
4
为什么不使用Task.Run() - Kyle Delaney
13个回答

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


2
这只是一种过于复杂的方法,将异步方法转换为async void,以便将行为从“点火并忘记”更改为“点火并崩溃”。您可以通过以下简单的方式实现相同的效果:async void OnErrorCrash(this Task task) => await task; - Theodor Zoulias

-3

很简单,只需调用asyncMethod().Result即可在不使用await的情况下调用。以下是示例代码,此处是fiddle

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");     
    }
}

-3
解决方案是在没有同步上下文的情况下将HttpClient启动到另一个执行任务中:
var submit = httpClient.PostAsync(uri, new StringContent(body, Encoding.UTF8,"application/json"));
var t = Task.Run(() => submit.ConfigureAwait(false));
await t.ConfigureAwait(false);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接