禁止“警告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); }