[英]c# async await strange warning CS1998: This async method lacks 'await' operators
[英]Suppress warning CS1998: This async method lacks 'await'
我有一個接口,其中包含一些返回Task
函數。 一些實現接口的類沒有任何等待,而其他類可能只是拋出 - 所以警告是虛假和煩人的。
是否可以抑制這些警告? 例如:
public async Task<object> test()
{
throw new NotImplementedException();
}
產量:
警告 CS1998:此異步方法缺少“await”運算符,將同步運行。 考慮使用 'await' 運算符來等待非阻塞 API 調用,或使用 'await Task.Run(...)' 在后台線程上執行 CPU 密集型工作。
我有一個帶有一些異步功能的接口。
我相信返回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;
}
helper 類還減少了 GC 否則必須收集的垃圾,因為具有相同返回類型的每個方法都可以共享其Task
和NotImplementedException
對象。
我的 AsyncEx 庫中有其他幾個“任務常量”類型示例。
另一種選擇,如果您想保持函數體簡單而不編寫代碼來支持它,只需使用 #pragma 抑制警告:
#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
保留 async 關鍵字(以防您想保留它)的另一種方法是使用:
public async Task StartAsync()
{
await Task.Yield();
}
填充該方法后,您可以簡單地刪除該語句。 我經常使用它,特別是當一個方法可能等待某些東西但不是每個實現實際上都這樣做時。
解決方案之間存在差異,嚴格來說您應該知道調用者將如何調用異步方法,但默認使用模式假設方法結果為“ .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);
}
}
}
我知道這是一個舊線程,也許這不會對所有用法都產生正確的效果,但是以下內容與在我尚未實現方法時能夠簡單地拋出 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;
}
}
正如 Stephen's Answer 的更新一樣,您不再需要編寫TaskConstants
類,因為有一個新的幫助方法:
public Task ThrowException()
{
try
{
throw new NotImplementedException();
}
catch (Exception e)
{
return Task.FromException(e);
}
}
你可以試試這個:
public async Task<object> test()
{
await Task.CompletedTask;
}
如果您已經鏈接到 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;
下面的 cs1998 可能會發生這種情況。
public async Task<object> Foo()
{
return object;
}
那么你可以在下面進行改造。
public async Task<object> Foo()
{
var result = await Task.Run(() =>
{
return object;
});
return result;
}
試試這個:
[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
如果您沒有任何等待,則返回 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());
}
首先,我找到了一個技巧來繞過此警告:
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,因此在Release版本中將其省略。 我不確定這種方法是否有副作用。
另外,我發現在asp.net核心(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!
}
}
全局配置/抑制它:
在 .editorconfig 中
# CS1998: Async method lacks 'await' operators and will run synchronously
dotnet_diagnostic.CS1998.severity = suggestion
在一個普通的、非高性能的應用程序中,不必要的異步的開銷可以忽略不計,而對常規編碼人員來說,全腦異步的好處更為重要。 (+ 額外的編譯器檢查等)
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();
您可以從方法中刪除 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();
}
}));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.