I've got an interface with some async functions. Some of the classes that implements the interface does not have anything to await, and some might just throw. It's a bit annoying with all the warnings.
When not using await in a async function.
Is it possible to suppress the message?
public async Task<object> test()
{
throw new NotImplementedException();
}
warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
I've got an interface with some async functions.
Methods returning Task
, I believe. async
is an implementation detail, so it can't be applied to interface methods.
Some of the classes that implements the interface does not have anything to await, and some might just throw.
In these cases, you can take advantage of the fact that async
is an implementation detail.
If you have nothing to await
, then you can just return Task.FromResult
:
public Task<int> Success() // note: no "async"
{
... // non-awaiting code
int result = ...;
return Task.FromResult(result);
}
In the case of throwing NotImplementedException
, the procedure is a bit more wordy:
public Task<int> Fail() // note: no "async"
{
var tcs = new TaskCompletionSource<int>();
tcs.SetException(new NotImplementedException());
return tcs.Task;
}
If you have a lot of methods throwing NotImplementedException
(which itself may indicate that some design-level refactoring would be good), then you could wrap up the wordiness into a helper class:
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 "task constant" type examples in my AsyncEx library.
Task<T>
inherits from Task
, the same solutions (Task.FromResult
, TaskCompletionSource
) work just fine. There isn't an easy and efficient way to create just a plain Task
like that, so it's best to create a Task<T>
and (implicitly) cast it to Task
. - Stephen ClearyTask
. Instead, your method will throw before it even gets a chance to create a Task
. I really think the best pattern is to define an async
method with no await
operators. This ensures the code within the method all gets treated as part of the Task
. - Bob Meyersawait Task.FromResult(0);
to your method. This should not have any significant perf impact (unlike Task.Yield()). - Bob Meyers
Another option, if you want to keep the body of the function simple and not write code to support it, is simply to suppress the warning with #pragma:
#pragma warning disable 1998
public async Task<object> Test()
{
throw new NotImplementedException();
}
#pragma warning restore 1998
If this is common enough, you could put the disable statement at the top of the file and omit the restore.
http://msdn.microsoft.com/en-us/library/441722ys(v=vs.110).aspx
Another way to preserve the async keyword (in case you want to keep it) is to use:
public async Task StartAsync()
{
await Task.Yield();
}
Once you populate the method you can simply remove the statement. I use this a lot especially when a method might await something but not every implementation actually does.
Task.Run
call. - Andrew ThekenTask.CompletedTask
does not seem to exist anymore. - Sebastián VansteenkisteTask.FromResult
is the better answer. For that matter, if you are going to throw an exception, it seems another answer has come into play regarding Task.FromException
making this never the ideal solution. Would you agree? - BlueMonkMN
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>();
}
Here's the type I added to make that possible.
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;
}
}
Just as an update to Stephen's Answer, you no longer need to write the TaskConstants
class as there is a new helper method:
return Task.FromException(new NotImplementedException());
There is difference in different solutions which you can find in answers and strictly speaking you should know how caller is going to call the async method, but with default usage pattern that assumes ".Wait()" on method result - "return Task.CompletedTask" is the best solution.
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.
Test Code:
[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);
}
}
}
#pragma
one seems to incur overhead. Probably just as much overhead as if instead of returning CompletedTask
you created and completed an AsyncOperation
. It’d be nice to be able to tell the compiler that it’s OK to skip that when the method runs synchronously anyway. - binkiTask.CompletedTask
is similar to Task.FromResult
? It would be interesting to know - I expect FromResult would be most analogous and still the best performer if you have to return a value. - BlueMonkMN
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();
}
Reactive and async/await are both amazing in and by themselves, but they also play well together.
Includes needed are:
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
It might be occured cs1998 below.
public async Task<object> Foo()
{
return object;
}
Then you can reform below.
public async Task<object> Foo()
{
var result = await Task.Run(() =>
{
return object;
});
return result;
}
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);
}
Here is some alternatives depending on your method signature.
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());
}
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();
Try this:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS1998:Await.Warning")]
You can drop the async keyword from the method and just have it return 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();
}
}));
}