取消警告CS4014:因为此调用未等待,当前方法的执行仍在继续…
本文关键字:方法 执行 继续 CS4014 警告 因为 等待 调用 取消 | 更新日期: 2023-09-27 17:52:52
这不是"如何在没有await的情况下安全地调用c#中的async方法"的副本。
如何很好地抑制以下警告?
警告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, e.g.:
// ...
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
// ...
}
已更新,由于原始接受的答案已被编辑,我已将接受的答案更改为使用c# 7.0丢弃的答案,因为我认为ContinueWith
在这里不合适。每当我需要记录"即发即弃"操作的异常时,我使用Stephen Cleary在这里提出的更详细的方法。
在c# 7中可以使用discards:
_ = WorkAsync();
您可以创建一个扩展方法来阻止该警告。扩展方法可以为空,也可以在其中添加.ContinueWith()
异常处理。
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()
扩展一起工作,而是可能会失败,异常:
在。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));
}
我有两种处理方法。
保存为丢弃变量(c# 7)
例子 _ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
自从c# 7中引入了discards,我现在认为这比抑制警告要好。因为它不仅抑制了警告,而且使"即发即弃"的意图更加明确。
此外,编译器将能够在发布模式下优化它。
直接抑制
#pragma warning disable 4014
...
#pragma warning restore 4014
是一个很好的解决方案,"炒了就忘了"。
存在此警告的原因是因为在许多情况下,您不打算使用不等待返回task的方法。当你确实想开火却忘记时,抑制警告是有意义的。
如果你不记得如何拼写#pragma warning disable 4014
,只需让Visual Studio为你添加它。按Ctrl +。打开"快速操作",然后打开"抑制CS2014"
All in All
仅仅为了抑制警告而创建一个需要更多时间来执行的方法是愚蠢的。
你可以用以下属性来修饰这个方法:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")]
static async Task StartWorkAsync()
{
WorkAsync();
// ...
}
基本上你是在告诉编译器你知道你在做什么,它不需要担心可能的错误。
这段代码的重要部分是第二个参数。"CS4014:"部分是抑制警告的部分。
一种简单的停止警告的方法是在调用Task时分配Task:
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, e.g.:
// ...
await Task.Delay(2000);
}
警告的原因是WorkAsync正在返回一个从未被读取或等待的 Task
。您可以将WorkAsync的返回类型设置为 void
,警告将消失。
当调用者需要知道工作线程的状态时,方法通常返回一个Task
。在"即发即弃"的情况下,应该返回void,以使调用方独立于被调用的方法。
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, e.g.:
// ...
await Task.Delay(2000);
}
为什么不把它包装在一个返回void的async方法中呢?有点长,但是使用了所有的变量。
static async Task StartWorkAsync()
{
async void WorkAndForgetAsync() => await WorkAsync();
WorkAndForgetAsync(); // no warning
}
我今天偶然发现了这个方法。你可以先定义一个委托,然后把async方法分配给这个委托。
delegate Task IntermediateHandler();
static async Task AsyncOperation()
{
await Task.Yield();
}
并这样命名
(new IntermediateHandler(AsyncOperation))();
…
我认为这是有趣的,编译器不会给出完全相同的警告,当使用委托