抑制警告CS1998:这种异步方法缺少"等待"

Sim*_*mon 88 asynchronous

我有一个带有一些异步功能的接口.实现该接口的一些类没有任何东西需要等待,有些可能只是抛出.所有警告都有点烦人.

不在异步函数中使用await时.

是否有可能压制消息?

public async Task<object> test()
{
    throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)

警告CS1998:此异步方法缺少'await'运算符并将同步运行.考虑使用'await'运算符等待非阻塞API调用,或'await Task.Run(...)'在后台线程上执行CPU绑定工作.

Ste*_*ary 95

我有一个带有一些异步功能的接口.

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

实现该接口的一些类没有任何东西需要等待,有些可能只是抛出.

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

如果您没有任何东西await,那么您可以返回Task.FromResult:

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

在投掷的情况下NotImplementedException,程序有点罗嗦:

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

如果你有很多方法抛出NotImplementedException(这本身可能表明某些设计级重构会很好),那么你可以将wordiness包装成一个帮助类:

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;
}
Run Code Online (Sandbox Code Playgroud)

辅助类还减少了GC本来必须收集的垃圾,因为具有相同返回类型的每个方法都可以共享它TaskNotImplementedException对象.

我的AsyncEx库中还有其他几个"任务常量"类型示例.

  • **警告:**此方法可能会导致问题,因为错误不会以您期望的方式传播.通常,调用者会希望您的方法中的异常在`Task`中浮出水面.相反,你的方法会在它有机会创建一个`Task`之前抛出.我真的认为最好的模式是定义一个没有`await`运算符的`async`方法.这可以确保方法中的代码都被视为`Task`的一部分. (8认同)
  • 要避免使用CS1998,可以在方法中添加`await Task.FromResult(0);`.这不应该有任何重大的性能影响(与Task.Yield()不同). (8认同)
  • 你能推荐一种返回类型只是Task的方法(没有结果吗?) (3认同)
  • 我没想到会丢失关键字。正如你所说,异步与接口无关。我的不好,谢谢。 (2认同)
  • @AndrewTheken:这些天,您可以执行return return.CompletedTask; -最简单的方法。 (2认同)
  • 如果您只需在“.csproj”中禁用 CS1998 警告,您将获得更清晰的代码。 (2认同)

Jam*_*cia 57

另一种选择,如果你想保持函数的主体简单而不是编写代码来支持它,只需用#pragma来抑制警告:

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

如果这很常见,您可以将disable语句放在文件的顶部并省略还原.

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


Sim*_*tes 35

另一种保留async关键字的方法(如果你想保留它)是使用:

public async Task StartAsync()
{
    await Task.Yield();
}
Run Code Online (Sandbox Code Playgroud)

填充方法后,您只需删除该语句即可.我经常使用它,特别是当一个方法可能等待某些东西但不是每个实现实际上都有.

  • 等待Task.CompletedTask; //可能是更好的选择 (11认同)
  • @SebastiánVansteenkiste .Net Framework 4.6-&gt;、UWP 1.0-&gt;、.Net Core 1.0-&gt; (2认同)

Rom*_*kij 11

您可以在答案中找到不同解决方案的不同之处,严格来说,您应该知道调用者将如何调用异步方法,但默认使用模式假设方法结果为" .Wait()" - " 返回Task.CompletedTask "是最好的解决方案.

    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 |
Run Code Online (Sandbox Code Playgroud)

注意:FromResult不能直接比较.

测试代码:

   [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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

}

  • 不幸的是,“#pragma”似乎会产生开销。可能与创建并完成“AsyncOperation”而不是返回“CompletedTask”一样多的开销。如果能够告诉编译器当该方法同步运行时可以跳过它,那就太好了。 (2认同)

Mat*_*att 10

就像Stephen's Answer的更新一样,您不再需要编写TaskConstants类,因为有一个新的帮助方法:

    public Task ThrowException()
    {
        try
        {
            throw new NotImplementedException();
        }
        catch (Exception e)
        {
            return Task.FromException(e);
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 不要这样做。堆栈跟踪不会指向您的代码。必须抛出异常才能完全初始化。 (4认同)

rrr*_*eee 9

我知道这是一个旧线程,也许这对所有用法都没有正确的效果,但是当我还没有实现一个方法时,以下就能够简单地抛出一个NotImplementedException,不改变方法签名.如果它有问题,我会很高兴知道它,但它对我来说几乎不重要:我只是在开发过程中使用它,所以它的表现并不是那么重要.不过,我很高兴听到为什么这是一个坏主意,如果是的话.

public async Task<object> test()
{
    throw await new AwaitableNotImplementedException<object>();
}
Run Code Online (Sandbox Code Playgroud)

这是我为了实现这一目的而添加的类型.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 9

你可以试试这个:

public async Task<object> test()
{
await Task.CompletedTask; 
}
Run Code Online (Sandbox Code Playgroud)