"경고 CS4014 :이 호출을 기다리지 않기 때문에 현재 메소드의 실행이 계속됩니다 ..."억제
이것은 "대기없이 C #에서 비동기 메서드를 안전하게 호출하는 방법" 과 중복되지 않습니다 .
다음 경고를 어떻게 잘 억제합니까?
경고 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에서는 이제 폐기를 사용할 수 있습니다 .
_ = 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()
위에 나열된 간단한 확장명 에서는 작동하지 않으며 예외로 인해 실패 할 수 있습니다.
An asynchronous module or handler completed while an asynchronous operation was still pending.
With .NET 4.5.2 it can be solved by using 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));
}
You can decorate the method with the following attribute:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")]
static async Task StartWorkAsync()
{
WorkAsync();
// ...
}
Basically you are telling the compiler that you know what you are doing and it does not need to worry about possible mistake.
The important part of this code is the second parameter. The "CS4014:" part is what suppresses the warning. You can write anything you want on the rest.
My two way of dealing with this.
Save it to a discard variable (C# 7)
Example
_ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
Since the introduction of discards in C# 7, I now consider this to be better than supressing the warning. Because it not only supresses the warning, but also makes the fire-and-forget intention clear.
Moreover, the compiler will be able to optimize it away in release mode.
Just suppress it
#pragma warning disable 4014
is a nice enough solution to "fire and forget".
The reason why this warning exists is because in many cases it is not your intention to use an method that returns task without awaiting it. Suppressing the warning when you do intend to fire and forget makes sense.
If you have trouble remembering how to spell #pragma warning disable 4014
, simply let Visual Studio add it for you. Press Ctrl+. to open "Quick Actions" and then "Suppress CS2014"
All in all
It's stupid to create a method that takes a few more ticks to execute, just for the purpose of suppressing a warning.
An easy way of stopping the warning is to simply assign the Task when calling it:
Task fireAndForget = WorkAsync(); // No warning now
And so in your original post you would do:
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);
}
The reason for the warning is WorkAsync is returning a Task
that is never read or awaited. You can set the return type of WorkAsync to void
and the warning will go away.
Typically a method returns a Task
when the caller needs to know the status of the worker. In the case of a fire-and-forget, void should be returned to resemble that the caller is independent of the called method.
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);
}
Why not wrap it inside an async method that returns void ? A bit lengthy but all variables are used.
static async Task StartWorkAsync()
{
async void WorkAndForgetAsync() => await WorkAsync();
WorkAndForgetAsync(); // no warning
}
I found this approach by accident today. You can define a delegate and assign the async method to the delegate first.
delegate Task IntermediateHandler();
static async Task AsyncOperation()
{
await Task.Yield();
}
and call it like so
(new IntermediateHandler(AsyncOperation))();
...
I thought it was interesting that the compiler wouldn't give the exact same warning when using the delegate.
'Programing' 카테고리의 다른 글
다른 파일 A에서 파일 B에 나타나는 줄을 제거하는 방법? (0) | 2020.06.21 |
---|---|
로딩 / 진행 표시기를 표시하는 가장 좋은 방법은 무엇입니까? (0) | 2020.06.21 |
네임 스페이스가 인식되지 않습니다 (있는 경우에도) (0) | 2020.06.21 |
GIT에서 부분 복귀를 할 수 있습니까 (0) | 2020.06.21 |
어떤 깊이에서든 이름으로 요소에 대한 XDocument 쿼리 (0) | 2020.06.21 |