这不是 "How to safely call an async method in C# without await" 的副本。
如何很好地抑制以下警告?
警告 CS4014:由于未等待此调用,因此在调用完成之前继续执行当前方法。考虑将“等待”运算符应用于调用结果。
一个简单的例子:
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
// ...
}
更新,由于 original accepted answer 已被编辑,我已将接受的答案更改为 the one using C# 7.0 discards,因为我认为 ContinueWith
在这里不合适。每当我需要记录即发即弃操作的异常时,我都会使用更精细的方法 proposed by Stephen Cleary here。
#pragma
不好?
您可以创建一个可以防止警告的扩展方法。扩展方法可以为空,或者您可以在此处使用 .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));
}
TplExtensions.Forget
。 Microsoft.VisualStudio.Threading
下还有很多优点。我希望它可以在 Visual Studio SDK 之外使用。
我的两种处理方式。
将其保存到丢弃变量 (C# 7)
例子
_ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
由于在 C# 7 中引入了丢弃,我现在认为这比抑制警告更好。因为它不仅抑制了警告,而且使“即发即弃”的意图清晰。
此外,编译器将能够在发布模式下对其进行优化。
压制就好
#pragma warning disable 4014
...
#pragma warning restore 4014
是“一劳永逸”的一个很好的解决方案。
存在此警告的原因是因为在许多情况下,您不打算使用不等待就返回任务的方法。当您确实打算开火并忘记时抑制警告是有道理的。
如果您无法记住如何拼写 #pragma warning disable 4014
,只需让 Visual Studio 为您添加即可。按 Ctrl+。打开“快速操作”,然后“抑制 CS2014”
总而言之
创建一个需要更多时间来执行的方法是愚蠢的,只是为了抑制警告。
[MethodImpl(MethodImplOptions.AggressiveInlining)] void Forget(this Task @this) { } /* ... */ obj.WorkAsync().Forget();
AggressiveInlining
时,无论出于何种原因,编译器都会忽略它
#pragma warning disable 4014
之类的错误代码,然后使用 #pragma warning restore 4014
恢复警告。它仍然可以在没有错误代码的情况下工作,但如果您不添加错误编号,它将抑制所有消息。
您可以使用以下属性装饰该方法:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")]
static async Task StartWorkAsync()
{
WorkAsync();
// ...
}
基本上你是在告诉编译器你知道你在做什么,它不需要担心可能的错误。
这段代码的重要部分是第二个参数。 “CS4014:”部分是抑制警告的原因。你可以在其余部分写任何你想要的东西。
[SuppressMessage("Compiler", "CS4014")]
抑制错误列表窗口中的消息,但输出窗口仍显示警告行
停止警告的一种简单方法是在调用任务时简单地分配任务:
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);
}
task
看起来像一个被遗忘的局部变量。几乎就像编译器应该给我另一个警告一样,“task
已分配,但它的值从未使用过”,除此之外它没有。此外,它使代码的可读性降低。我自己使用 this 方法。
fireAndForget
......所以我希望它从此不再被引用。
警告的原因是 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 的异步方法中?有点冗长,但使用了所有变量。
static async Task StartWorkAsync()
{
async void WorkAndForgetAsync() => await WorkAsync();
WorkAndForgetAsync(); // no warning
}
我今天偶然发现了这种方法。您可以先定义一个委托并将异步方法分配给该委托。
delegate Task IntermediateHandler();
static async Task AsyncOperation()
{
await Task.Yield();
}
并这样称呼它
(new IntermediateHandler(AsyncOperation))();
...
我认为有趣的是,编译器在使用委托时不会给出完全相同的警告。
(new Func<Task>(AsyncOperation))()
尽管 IMO 它仍然有点过于冗长。
不定期副业成功案例分享
_ = ...
。#pragma warning disable CSxxxx
看起来比丢弃更难看;)