禁止“警告CS4014:由于此调用未被等待,当前方法的执行继续…”

这不是“如何在不等待的情况下安全地调用C#中的asynchronous方法”的复制。

我如何很好地抑制以下警告?

警告CS4014:由于此呼叫未等待,所以在呼叫完成之前继续执行当前方法。 考虑将“await”运算符应用于调用的结果。

一个简单的例子:

static async Task WorkAsync() { await Task.Delay(1000); Console.WriteLine("Done!"); } static async Task StartWorkAsync() { WorkAsync(); // I want fire-and-forget // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); } 

我尝试过但不喜欢的东西:

 static async Task StartWorkAsync() { #pragma warning disable 4014 WorkAsync(); // I want fire-and-forget here #pragma warning restore 4014 // ... } static async Task StartWorkAsync() { var ignoreMe = WorkAsync(); // I want fire-and-forget here // ... } 

您可以创build一个将防止警告的扩展方法。 扩展方法可以是空的,也可以使用.ContinueWith()添加exception处理。

 static class TaskExtensions { public static void Forget(this Task task) { task.ContinueWith( t => { WriteLog(t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } } public async Task StartWorkAsync() { this.WorkAsync().Forget(); } 

但是, ASP.NET计算正在运行的任务的数量,所以它不能与上面列出的简单的Forget()扩展一起使用,而是可能会失败并产生exceptionAn asynchronous module or handler completed while an asynchronous operation was still pending.

使用.NET 4.5.2可以通过使用HostingEnvironment.QueueBackgroundWorkItem来解决:

 public static Task HandleFault(this Task task, CancellationToken cancelToken) { return task.ContinueWith( t => { WriteLog(t.Exception); }, cancelToken, TaskContinuationOptions.OnlyOnFaulted TaskScheduler.Default); } public async Task StartWorkAsync() { System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem( cancelToken => this.WorkAsync().HandleFault(cancelToken)); } 

您可以使用以下属性修饰该方法:

 [System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")] static async Task StartWorkAsync() { WorkAsync(); // ... } 

基本上,你告诉编译器,你知道你在做什么,并不需要担心可能的错误。

这个代码的重要部分是第二个参数。 “CS4014:”部分是压制警告的部分。 你可以写任何你想要的东西。

问候,法比奥

我处理这个问题的两种方法。

只是压制它

#pragma warning disable是一个很好的解决scheme,“消防和忘记”。

这个警告存在的原因是因为在许多情况下,您不打算使用不等待它的任何方法返回任务。 当你打算开火时忘记警告是有道理的。

如果您在记忆如何拼写#pragma warning disable 4014遇到问题,只需让Visual Studio为您添加即可。 按下Ctrl +。 打开“快速行动”,然后“取消CS2014”

保存到一个局部variables

var task = Task.Run(() => DoMyStuff()).ConfigureAwait(false);

由于没有后续的task调用,所以在释放模式下,局部variables应该立即被优化掉,就像它永远不会在那里一样。 实际上,我怀疑编译器甚至会创build本地variables(有人可以用反编译器来确认它)。

总而言之

创build一个需要执行几个滴答的方法是愚蠢的,只是为了压制警告。

阻止警告的简单方法是在调用任务时简单地分配任务:

 Task fireAndForget = WorkAsync(); // No warning now 

所以在你原来的文章中,你会这样做:

 static async Task StartWorkAsync() { // Fire and forget var fireAndForget = WorkAsync(); // Tell the compiler you know it's a task that's being returned // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); } 

警告的原因是WorkAsync正在返回一个从不读取或等待的任务。 您可以将WorkAsync的返回types设置为无效,并且警告将消失。

通常情况下,当调用者需要知道工作者的状态时,方法返回一个Task。 在发生遗忘的情况下,应该返回类似于调用者独立于调用方法的空白。

 static async void WorkAsync() { await Task.Delay(1000); Console.WriteLine("Done!"); } static async Task StartWorkAsync() { WorkAsync(); // no warning since return type is void // more unrelated async/await stuff here, eg: // ... await Task.Delay(2000); }