我有一些带有异步函数的接口。实现该接口的一些类没有任何东西需要等待,有些可能只是抛出。所有警告都有点烦人。
在async函数中不使用await时。
是否可以取消该消息?
public async Task<object> test()
{
throw new NotImplementedException();
}
警告CS1998:此异步方法缺少'await'运算符并将运行 同步。考虑使用'await'运算符等待 非阻塞API调用,或'await Task.Run(...)'来执行CPU绑定工作 在后台线程上。
答案 0 :(得分:90)
我有一些带有异步功能的接口。
我相信返回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本来必须收集的垃圾,因为具有相同返回类型的每个方法都可以共享其Task
和NotImplementedException
个对象。
答案 1 :(得分:52)
另一种选择,如果你想保持函数的主体简单而不是编写代码来支持它,只需用#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
答案 2 :(得分:32)
保留async关键字的另一种方法(如果你想保留它)是使用:
public async Task StartAsync()
{
await Task.Yield();
}
填充方法后,您只需删除该语句即可。 我经常使用它,特别是当一个方法可能等待某些东西但不是每个实现实际上都有。
答案 3 :(得分:9)
正如Stephen's Answer的更新一样,您不再需要编写TaskConstants
类,因为有一个新的帮助方法:
return Task.FromException(new NotImplementedException());
答案 4 :(得分:9)
解决方案之间存在差异,严格来说,您应该知道调用方将如何调用异步方法,但默认使用模式假定方法结果为“.Wait()” - “返回Task.CompletedTask < / strong>“是最好的解决方案。
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);
}
}
}
答案 5 :(得分:8)
我知道这是一个老线程,也许这对所有用法都没有产生正确的效果,但是下面的内容非常接近我能够简单地抛出一个NotImplementedException,当我没有&#39 ; t尚未实现方法,而不改变方法签名。如果它有问题我会很高兴知道它,但它对我来说几乎不重要:我只是在开发过程中使用它,所以它的表现并不是那么重要。尽管如此,我仍然很高兴听到为什么这是一个坏主意,如果是的话。
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;
}
}
答案 6 :(得分:3)
如果您已经链接到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 :(得分:3)
下面可能会出现cs1998。
public async Task<object> Foo()
{
return object;
}
然后你可以在下面进行改革。
public async Task<object> Foo()
{
var result = await Task.Run(() =>
{
return object;
});
return result;
}
答案 8 :(得分:1)
如果您没有等待任何东西,请返回Task.FromResult
public Task<int> Success() // note: no "async"
{
... // Do not have await code
var result = ...;
return Task.FromResult(result);
}
答案 9 :(得分:1)
根据您的方法签名,以下是一些备选方案。
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());
}
答案 10 :(得分:1)
尝试一下:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS1998:Await.Warning")]
答案 11 :(得分:0)
首先,我找到了一个技巧来绕过此警告:
int main()
{
std::vector<int> v = {1,2,3,1,6,2,1};
const int currentVal = 1;
const auto itf = std::find(v.cbegin(), v.cend(), currentVal);
const auto itb = std::find(v.crbegin(), v.crend(), currentVal);
if(itf != v.cend()){
std::cout << "front pos: " << std::distance(v.cbegin(), itf) << std::endl;
std::cout << "back pos : " << (v.size() - std::distance(v.crbegin(), itb) - 1) << std::endl;
}
else{
std::cout << currentVal << " is not found." << std::endl;
}
return 0;
}
这是一个伪代码,用于禁用asycn方法中缺少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();
}
的警告!该 await 关键字的存在将欺骗编译器不发出警告,即使我们知道它永远不会被调用!因为条件是await
,所以它总是返回三进制条件(?:)的第一部分,并且由于此var是不使用的var,因此在Release版本中将省略它。我不确定这种方法是否有副作用。
此外,我发现此简单方法用于asp.net核心(TagHelper.cs)的源代码中,但是它需要从方法签名行中删除true
关键字:
async
这是更完整的代码:
return Task.CompletedTask;
答案 12 :(得分:0)
您可以尝试以下方法:
public async Task<object> test()
{
await Task.CompletedTask;
}
答案 13 :(得分:0)
全局配置/抑制它:
在 .editorconfig 中
# CS1998: Async method lacks 'await' operators and will run synchronously
dotnet_diagnostic.CS1998.severity = suggestion
在一个普通的、非高性能的应用程序中,不必要的异步的开销可以忽略不计,而对于常规编码人员来说,全脑异步的好处更为重要。 (+ 额外的编译器检查等)
答案 14 :(得分:-1)
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();
答案 15 :(得分:-1)
您可以从方法中删除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();
}
}));
}