取消警告 CS1998: 这个异步方法缺少“等待”

我有一个返回 Task的函数的接口。一些实现接口的类不需要等待任何东西,而其他类可能只需要抛出——所以这些警告是虚假的和令人讨厌的。

有没有可能压制这些警告? 例如:

public async Task<object> test()
{
throw new NotImplementedException();
}

收益率:

警告 CS1998: 这个异步方法没有等待操作符,将会运行 考虑使用“ wait”操作符等待 non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

81041 次浏览

我有一个带有异步函数的接口。

返回 Task的方法,我相信。 async是一个实现细节,因此它不能应用于接口方法。

有些实现接口的类不需要等待任何东西,有些可能只是抛出。

在这些情况下,您可以利用 async是一个实现细节这一事实。

如果你没有 await,那么你可以返回 Task.FromResult:

public Task<int> Success() // note: no "async"
{
... // non-awaiting code
int result = ...;
return Task.FromResult(result);
}

在抛出 NotImplementedException的情况下,这个过程有点冗长:

public Task<int> Fail() // note: no "async"
{
var tcs = new TaskCompletionSource<int>();
tcs.SetException(new NotImplementedException());
return tcs.Task;
}

如果你有很多抛出 NotImplementedException的方法(它本身可能表明一些设计级别的重构是好的) ,那么你可以把冗长的内容包装成一个助手类:

public static class TaskConstants<TResult>
{
static TaskConstants()
{
var tcs = new TaskCompletionSource<TResult>();
tcs.SetException(new NotImplementedException());
NotImplemented = tcs.Task;
}


public static Task<TResult> NotImplemented { get; private set; }
}


public Task<int> Fail() // note: no "async"
{
return TaskConstants<int>.NotImplemented;
}

The helper class also reduces garbage that the GC would otherwise have to collect, since each method with the same return type can share its Task and NotImplementedException objects.

I have several other AsyncEx 库中的“任务常量”类型示例.

In case you already link against Reactive Extension, you can also do:

public async Task<object> NotImplemented()
{
await Observable.Throw(new NotImplementedException(), null as object).ToTask();
}


public async Task<object> SimpleResult()
{
await Observable.Return(myvalue).ToTask();
}

反应式和异步/等待式本身都令人惊叹,但它们也可以很好地结合在一起。

Includes needed are:

using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;

另一种选择是,如果您想保持函数体的简单性,而不想编写代码来支持它,那么只需使用 # 杂注来禁止发出警告:

#pragma warning disable 1998
public async Task<object> Test()
{
throw new NotImplementedException();
}
#pragma warning restore 1998

如果这种情况足够常见,那么可以在文件的顶部放置禁用语句,省略还原。

Http://msdn.microsoft.com/en-us/library/441722ys(v=vs.110).aspx

另外一种保留 sync 关键字的方法(如果您想保留它的话)是使用:

public async Task StartAsync()
{
await Task.Yield();
}

一旦填充了该方法,就可以简单地删除该语句。 I use this a lot especially when a method might await something but not every implementation actually does.

I know this is an old thread, and perhaps this won't have the right effect for all usages, but the following is as close as I can get to being able to simply throw a NotImplementedException when I haven't yet implemented a method, without altering the method signature. If it's problematic I'd be happy to know about it, but it barely matters to me: I only use this while in development anyway, so how it performs isn't all that important. Still, I'd be happy to hear about why it's a bad idea, if it is.

public async Task<object> test()
{
throw await new AwaitableNotImplementedException<object>();
}

下面是我为了实现这一点而添加的类型。

public class AwaitableNotImplementedException<TResult> : NotImplementedException
{
public AwaitableNotImplementedException() { }


public AwaitableNotImplementedException(string message) : base(message) { }


// This method makes the constructor awaitable.
public TaskAwaiter<AwaitableNotImplementedException<TResult>> GetAwaiter()
{
throw this;
}
}

它可能发生在 CS1998下面。

public async Task<object> Foo()
{
return object;
}

然后你可以在下面改造。

public async Task<object> Foo()
{
var result = await Task.Run(() =>
{
return object;
});
return result;
}
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();

您可以从该方法中删除异步关键字,只需让它返回 Task;

    public async Task DoTask()
{
State = TaskStates.InProgress;
await RunTimer();
}


public Task RunTimer()
{
return new Task(new Action(() =>
{
using (var t = new time.Timer(RequiredTime.Milliseconds))
{
t.Elapsed += ((x, y) => State = TaskStates.Completed);
t.Start();
}
}));
}

Just as an update to Stephen's Answer, you no longer need to write the TaskConstants class as there is a new helper method:

    public Task ThrowException()
{
try
{
throw new NotImplementedException();
}
catch (Exception e)
{
return Task.FromException(e);
}
}

If you don't have anything to await then return Task.FromResult

public Task<int> Success() // note: no "async"
{
... // Do not have await code
var result = ...;
return Task.FromResult(result);
}

下面是一些取决于您的方法签名的备选方案。

    public async Task Test1()
{
await Task.CompletedTask;
}


public async Task<object> Test2()
{
return await Task.FromResult<object>(null);
}


public async Task<object> Test3()
{
return await Task.FromException<object>(new NotImplementedException());
}

解决方案和严格地说,您应该知道调用方将如何调用异步方法,这两者之间存在差异,但是默认使用模式假定“。“等待()”的方法结果-“ 完成任务”是最好的解决方案。

    BenchmarkDotNet=v0.10.11, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233537 Hz, Resolution=309.2589 ns, Timer=TSC
.NET Core SDK=2.1.2
[Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Clr    : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2600.0
Core   : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT




Method |  Job | Runtime |         Mean |       Error |      StdDev |       Median |          Min |          Max | Rank |  Gen 0 |  Gen 1 |  Gen 2 | Allocated |
--------------- |----- |-------- |-------------:|------------:|------------:|-------------:|-------------:|-------------:|-----:|-------:|-------:|-------:|----------:|
CompletedAwait |  Clr |     Clr |    95.253 ns |   0.7491 ns |   0.6641 ns |    95.100 ns |    94.461 ns |    96.557 ns |    7 | 0.0075 |      - |      - |      24 B |
Completed |  Clr |     Clr |    12.036 ns |   0.0659 ns |   0.0617 ns |    12.026 ns |    11.931 ns |    12.154 ns |    2 | 0.0076 |      - |      - |      24 B |
Pragma |  Clr |     Clr |    87.868 ns |   0.3923 ns |   0.3670 ns |    87.789 ns |    87.336 ns |    88.683 ns |    6 | 0.0075 |      - |      - |      24 B |
FromResult |  Clr |     Clr |   107.009 ns |   0.6671 ns |   0.6240 ns |   107.009 ns |   106.204 ns |   108.247 ns |    8 | 0.0584 |      - |      - |     184 B |
Yield |  Clr |     Clr | 1,766.843 ns |  26.5216 ns |  24.8083 ns | 1,770.383 ns | 1,705.386 ns | 1,800.653 ns |    9 | 0.0877 | 0.0038 | 0.0019 |     320 B |
CompletedAwait | Core |    Core |    37.201 ns |   0.1961 ns |   0.1739 ns |    37.227 ns |    36.970 ns |    37.559 ns |    4 | 0.0076 |      - |      - |      24 B |
Completed | Core |    Core |     9.017 ns |   0.0690 ns |   0.0577 ns |     9.010 ns |     8.925 ns |     9.128 ns |    1 | 0.0076 |      - |      - |      24 B |
Pragma | Core |    Core |    34.118 ns |   0.4576 ns |   0.4281 ns |    34.259 ns |    33.437 ns |    34.792 ns |    3 | 0.0076 |      - |      - |      24 B |
FromResult | Core |    Core |    46.953 ns |   1.2728 ns |   1.1905 ns |    46.467 ns |    45.674 ns |    49.868 ns |    5 | 0.0533 |      - |      - |     168 B |
Yield | Core |    Core | 2,480.980 ns | 199.4416 ns | 575.4347 ns | 2,291.978 ns | 1,810.644 ns | 4,085.196 ns |   10 | 0.0916 |      - |      - |     296 B |

Note: FromResult can't be directly compared.

测试代码:

   [RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
[ClrJob, CoreJob]
[HtmlExporter, MarkdownExporter]
[MemoryDiagnoser]
public class BenchmarkAsyncNotAwaitInterface
{
string context = "text context";
[Benchmark]
public int CompletedAwait()
{
var t = new CompletedAwaitTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}


[Benchmark]
public int Completed()
{
var t = new CompletedTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}


[Benchmark]
public int Pragma()
{
var t = new PragmaTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}


[Benchmark]
public int Yield()
{
var t = new YieldTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}


[Benchmark]
public int FromResult()
{
var t = new FromResultTest();
var t2 = t.DoAsync(context);
return t2.Result;
}


public interface ITestInterface
{
int Length { get; }
Task DoAsync(string context);
}


class CompletedAwaitTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.CompletedTask;
}
}


class CompletedTest : ITestInterface
{
public int Length { get; private set; }
public Task DoAsync(string context)
{
Length = context.Length;
return Task.CompletedTask;
}
}


class PragmaTest : ITestInterface
{
public int Length { get; private set; }
#pragma warning disable 1998
public async Task DoAsync(string context)
{
Length = context.Length;
return;
}
#pragma warning restore 1998
}


class YieldTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.Yield();
}
}


public interface ITestInterface2
{
Task<int> DoAsync(string context);
}


class FromResultTest : ITestInterface2
{
public async Task<int> DoAsync(string context)
{
var i = context.Length;
return await Task.FromResult(i);
}
}

}

试试这个:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS1998:Await.Warning")]

参见: Https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.suppressmessageattribute?view=netframework-4.7.2

你可以试试这个:

public async Task<object> test()
{
await Task.CompletedTask;
}

在全球范围内配置/抑制它:

编辑配置

# CS1998: Async method lacks 'await' operators and will run synchronously
dotnet_diagnostic.CS1998.severity = suggestion

在一个普通的、并不高性能的应用程序中,不必要的异步的开销是可以忽略的,而对于普通编码人员来说,全程异步的好处更为重要。(+ 额外的编译器检查等)

Cleanest wait to suppress this warning is to just use await Task.CompletedTask; before throwing. This functions as a no-op

public async Task SomeMethod()
{
await Task.CompletedTask;
throw new NotImplementedException();
}

使用已产生异常的抛出

public async Task<object> DoSomethingAsync()
{
throw await Task.FromException<NotImplementedException>(new NotImplementedException());
}

从方法中删除异步部分。

  • 如果返回一个 Task: 使用 Task.CompletedTask
  • 如果返回 Task < object > ,请使用 Task.FromResult(object)