首页 文章

抑制警告CS1998:此异步方法缺少'await'

提问于
浏览
72

我对所有的警告都有些恼火 .

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

是否有可能压制消息?

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

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

14 回答

  • 8

    我有一些带有异步功能的界面 .

    方法返回 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 (它本身可能表明某些设计级重构会很好),那么你可以将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;
    }
    

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

    我还有其他几个"task constant" type examples in my AsyncEx library .

  • 1

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

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

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

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

  • 50

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

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

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

  • 0

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

    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;
        }
    }
    
  • 1

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

    return Task.FromException(new NotImplementedException());
    
  • 32

    解决方案之间存在差异,严格来说,您应该知道调用方将如何调用异步方法,但使用默认使用模式假定".Wait()"方法结果 - “ return 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 |
    

    注意: 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);
            }
        }
    

    }

  • -1

    如果您已经链接到Reactive Extension,您还可以执行以下操作:

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

    Reactive和async / await既令人惊叹又独立,但它们也能很好地协同工作 .

    包括需要的是:

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

    它可能发生在下面的cs1998 .

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

    然后你可以在下面改革 .

    public async Task<object> Foo()
    {
        var result = await Task.Run(() =>
        {
            return object;
        });
        return result;
    }
    
  • -1

    如果您没有任何要等待的东西,请返回Task.FromResult

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

    根据您的方法签名,这里有一些替代方案 .

    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());
        }
    
  • 1

    试试这个:

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

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

  • 85

    首先,我发现了一个绕过这个警告的技巧:

    public async Task<object> test()
    {
        //a pseudo code just to disable the warning about lack of await in async code!
        var xyz = true ? 0 : await Task.FromResult(0); //use a var name that's not used later
    
        //... your code statements as normal, eg:
        //throw new NotImplementedException();
    }
    

    这是一个伪代码,用于在asycn方法中禁用有关缺少 await 的警告!那个 await 关键字的存在会导致编译器欺骗不提出警告,即使我们知道它永远不会被调用!因为条件是 true 它总是返回三元条件(?:)的第一部分,并且因为这个var是非使用var,它将在发布版本中省略 . 我不确定这种方法是否有任何副作用 .


    另外,我发现这个简单的方法在asp.net core(TagHelper.cs)的源代码中使用,但是需要从方法签名行中删除 async 关键字:

    return Task.CompletedTask;

    这是更完整的代码:

    public abstract class TagHelper : ITagHelper, ITagHelperComponent
    {
    
        public virtual void Process(TagHelperContext context, TagHelperOutput output)
        {
        }
    
        public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            Process(context, output);
            return Task.CompletedTask; // *** this will avoid the lacks await warning!
        }
    }
    
  • 3
    // This is to get rid of warning CS1998, please remove when implementing this method.
    await new Task(() => { }).ConfigureAwait(false);
    throw new NotImplementedException();
    
  • 8

    您可以从方法中删除async关键字,然后让它返回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();
                }
            }));
        }
    

相关问题