Take for example the following interface:
interface IOracle
{
Task<string> GetAnswerAsync(string question);
}
Some implementations of this interface might use async
/await
. Others might not need to. For example, consider this simple toy implementation.
class SimpleOracle
{
public Dictionary<string, string> Lookup { get; set; }
// Warning CS1998: This async method lacks 'await' operators
// and will run synchonously.
public async Task<string> GetAnswerAsync(string question)
{
string answer = Lookup[question];
return answer;
}
}
The compiler warning CS1998 of course makes sense. The usual suggestion is to remove the async
keyword and use Task.FromResult
, but it misses a subtle issue. What if the code throws an exception? Then that code transform changes the behavior of the method: the async
version will wrap any exception in a Task
; the non-async
version will not, without an explict try
-catch
.
Leaving the async
keyword works exactly as I want, but it produces a compiler warning, and I don't think suppressing those is wise.
How should I refactor my method implementation to not produce a compiler warning while also wrapping all exceptions with Task
as any other async
method would?
Return Task from asynchronous method When a method returns a task, we can use the await keyword to call it. Note: The await keyword should be within a function qualified by an async keyword (in other words asynchronous), otherwise the compiler will treat it as a normal synchronous function.
Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.
The simplest way to execute a method asynchronously is to start executing the method by calling the delegate's BeginInvoke method, do some work on the main thread, and then call the delegate's EndInvoke method. EndInvoke might block the calling thread because it does not return until the asynchronous call completes.
Async/await helps you write synchronous-looking JavaScript code that works asynchronously. Await is in an async function to ensure that all promises that are returned in the function are synchronized.
The mechanical translation I use to convert from the async
version that yields compiler warning CS1998 to a non-async
version that behaves identically is as follows.
async
keyword.try
-catch
.TaskCompletionSource<T>
called tcs
before the try
-catch
.return <expr>;
with tcs.SetResult(<expr>);
followed by return tcs.Task;
.catch
block to call tcs.SetException(e)
followed by return tcs.Task;
.For example:
public Task<string> GetAnswerAsync(string question)
{
var tcs = new TaskCompletionSource<string>();
try
{
string answer = Lookup[question];
tcs.SetResult(answer);
return tcs.Task;
}
catch (Exception e)
{
tcs.SetException(e);
return tcs.Task;
}
}
This can be expressed more generally by the following, although I don't know if it would be appropriate to actually introduce such a helper method into a codebase.
public static Task<T> AsyncPattern(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
try
{
tcs.SetResult(func());
}
catch (Exception e)
{
tcs.SetException(e);
}
return tcs.Task;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With