c#: Chain asynchronous methods - c#

I've found a piece of code showing how to chain asynchronous methods. Here is the code:
public static class ExtensionMethod
{
public static async Task<TResult> MapAsync<TSource, TResult>(
this Task<TSource> #this,
Func<TSource, Task<TResult>> fn)
{
return await fn(await #this);
}
}
public partial class Program
{
public async static Task<int> FunctionA
(int a) => await Task.FromResult(a * 1);
public async static Task<int> FunctionB(
int b) => await Task.FromResult(b * 2);
public async static Task<int> FunctionC(
int c) => await Task.FromResult(c * 3);
public async static void AsyncChain()
{
int i = await FunctionC(10)
.MapAsync(FunctionB)
.MapAsync(FunctionA);
Console.WriteLine("The result = {0}", i);
}
}
But I don't understand why inside the extension method MapAsync we have await fn(await #this)?
Can someone explain me this, please?

The reason for this is because in order to get the value of the previous call (in this case the value stored within the Task #this) it must be awaited. Because await is now being used in the method and it must be marked as async, you can now no longer simply return the result from fn because it's a Task. (As I'm sure you are aware, and in very simple terms, marking the method as async means that the method signature sort of ignores the Task and just wants an instance of the generic type as the return or nothing if it's not using the genric version of Task.)
In response to your comment about chaining both sync vs async methods, this approach of using Task would still work for sync methods, you just have to pretend that its async by wrapping the result in a task (which is already marked as completed). Something like this:
public async static Task<int> AsyncFunction(int x)
=> await SomeAsyncMethodThatReturnsTaskOfInt();
public static Task<int> SyncFunction(int x)
=> Task.FromResult(SomeSyncMethodThatReturnsInt());
public async static void AsyncChain()
{
int i = await AsyncFunction(10)
.MapAsync(SyncFunction);
Console.WriteLine("The result = {0}", i);
}
You can remove all the async/awaits from the FunctionA, FunctionB and FunctionC definitions as they can just return the task.
There is a nice article on Eliding await by Stephen Cleary for a better explanation of when you should and shouldn't use await when the only thing the method is doing is returning Task.
Having said all that, Gusman's comment is completely correct that this is total overkill for a fairly simple ContinueWith

Related

NonAsync method going throw Async for single flow calls

I'm creating a .NET Standard library with several methods, each having regular and async version.
So one method for example is:
public static int DoSomethingOne(string value) { ... }
public static async Task<int> DoSomethingOneAsync(string value) { ... }
Now they are doing some string manipulation and also calling DB with EF functions.
Currently I have these methods in complete separate flow but I have seen example of internal methods being joined meaning non async going throw async with if condition and returned with .GetAwaiter().GetResult();
This approach seems more DRY, no double code.
So the question: is that structure valid or should I stick to separate flow?
Also to note that I already have segments of logic in shared methods that are async agnostic, but still some code is doubled, like calls to those shared method and few other lines.
To extend the example:
Currently have:
public static int DoSomethingOne(string value)
{
return DoSomethingOneInternal(value);
}
public static async Task<int> DoSomethingOneAsync(string value, CancellationToken cancellationToken)
{
return await DoSomethingOneInternalAsync(value, cancellationToken).ConfigureAwait(false);
}
private static int DoSomethingOneInternal(string value)
{
var input = DoStringChangeOne(value);
CallDbOne(input);
var output = DoStringChangeTwo(input);
var count = CallDbTwo(output);
return count;
}
private static async Task<int> DoSomethingOneInternalAsync(string value, CancellationToken cancellationToken) { ... }
{
var input = DoStringChangeOne(value);
await CallDbOneAsync(input).ConfigureAwait(false);
var output = DoStringChangeTwo(input);
var count = await CallDbTwoAsync(output).ConfigureAwait(false);
return count;
}
Alternatively could write:
public static int DoSomethingOne(string value)
{
return DoSomethingOneInternalAsync(value, null, isAsync: false).GetAwaiter().GetResult();
}
public static async Task<int> DoSomethingOneAsync(string value, CancellationToken cancellationToken)
{
return await DoSomethingOneInternalAsync(value, cancellationToken, isAsync: true).ConfigureAwait(false);
}
private static int DoSomethingOneInternalAsync(string s, CancellationToken? cancellationToken, bool isAsync)
{
var input = DoStringChangeOne(value);
if(isAsync) {
await CallDbOneAsync(input).ConfigureAwait(false);
}
else {
CallDbOne(input);
}
var output = DoStringChangeTwo(input);
var count = isAsync ? await CallDbTwoAsync(output).ConfigureAwait(false) : CallDbTwo(output);
return count;
}
Now there are around 10 method like this, and they have 2 to 4 depth levels of calls to internal submethods for better structure.
Also to add that async version are 'main' ones and more often used as to why they have direct flow, while nonAsync are not regularly used so they are redirected in option 2.
is that structure valid or should I stick to separate flow?
It's valid. Whether you should use it or not is up to you. The benefits of the "boolean argument hack" is that your code is DRY - in particular, this means that if there's a bugfix applied to one method, then both the synchronous and asynchronous versions always get that bugfix. But if these are relatively small methods, then the extra boilerplate may not be worthwhile.

Warning message in IAsyncEnumerable when it lacks the await operator

When calling a method like this without doing an await task, we can return the following:
public Task<bool> GetBoolAsync()
{
return Task.FromResult(true);
}
What would be the equivalent for a IAsyncEnumerable<> and avoid the warning.
async IAsyncEnumerable<bool> GetBoolsAsync() // <- Ugly warning
{
yield return true;
yield break;
}
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 would probably write a synchronous iterator method, then use ToAsyncEnumerable from the System.Linq.Async package to convert it to the async version. Here's a complete example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
await foreach (bool x in GetBoolsAsync())
{
Console.WriteLine(x);
}
}
// Method to return an IAsyncEnumerable<T>. It doesn't
// need the async modifier.
static IAsyncEnumerable<bool> GetBoolsAsync() =>
GetBools().ToAsyncEnumerable();
// Regular synchronous iterator method.
static IEnumerable<bool> GetBools()
{
yield return true;
yield break;
}
}
This complies with the interface (of using IAsyncEnumerable<T>) but allows a synchronous implementation, with no warnings. Note that the async modifier itself is not part of a method signature - it's an implementation detail. So a method specified in an interface as returning a Task<T>, IAsyncEnumerable<T> or whatever can be implemented with an async method, but doesn't have to be.
Of course for a simple example where you just want to return a single element, you could use ToAsyncEnumerable on an array, or the result of Enumerable.Repeat. For example:
static IAsyncEnumerable<bool> GetBoolsAsync() =>
new[] { true }.ToAsyncEnumerable();
I think you are looking for TaskCompletionSource. This gives you the most flexibility. You can set exceptions on the task, mark it incomplete etc. Alternatively Task.FromResult.
In many scenarios, it is useful to enable a Task to represent
an external asynchronous operation. TaskCompletionSource is
provided for this purpose. It enables the creation of a task that can
be handed out to consumers. The consumers can use the members of the
task the same way as they would in any other scenario handling task
member variables.
Consider the following options for both, I include the first, but you can't return a Task.CompletedTask<T>, but if you just want to return a completed Task, eg cause maybe you had some out parameters that have been set, then that might be your answer.
static async Task SomeMethod()
{
await Task.CompletedTask;
}
or - because we can't use await without async
static Task<bool> SomeOtherMethod()
{
var taskSource = new TaskCompletionSource<bool>();
taskSource.SetResult(true);
return taskSource.Task;
}
or (.Net 4.5+)
static Task<bool> SomeEvenOtherMethod()
{
return Task.FromResult(true);
}
or the async variant of the above
static async Task<bool> SomeEvenOtherMethod()
{
var taskSource = new TaskCompletionSource<bool>();
taskSource.SetResult(true);
return (await taskSource.Task);
}
Alternatively: (.Net 4.5+)
static async Task<bool> SomeEvenOtherMethod()
{
return(await Task.FromResult(true));
}
And with an IAsyncEnumerable
static async IAsyncEnumerable<bool> GetBoolsAsync()
{
var t = await SomeOtherMethod();
yield return t;
}
Or (.Net 4.5+)
static async IAsyncEnumerable<bool> GetBoolsAsync()
{
yield return await Task.FromResult(true);
}

Where is the return statement in async/await

I have probably worked myself into a rather immature confusion. Please refer the code below (console app)
namespace Tasks101
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Blah();
}
private async Task Blah()
{
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
}
private async void ReturnsVoid()
{
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
}
private void Nothing()
{
}
}
}
My question is that in Blah() method I don't have any explicit return statement yet when this executes
var x = p.Blah();
the type of x is Task. Again I have no return statement in ReturnsVoid method but that compiles too.
So the questions are
What is returning a Task from the Blah method without my having a return statement there and why is that same thing not returning anything from ReturnsVoid method.
How do I control what gets returned from the Blah method? What if I had two await statements there one after the other?
The async keyword transforms the method and constructs the returned Task instance. There is nothing returned from the async void method because it returns void; this lack of a Task is one reason why you should avoid async void. async void is not a natural asynchronous method signature; it is only supported so that event handlers may be async.
If you want to return a value, then you should have the method return a Task<T>, e.g., Task<int> BlahAsync(), and then you can just return the value directly, e.g., return 13; The number of awaits in the method has nothing to do with it. When the method executes the actual return (e.g., return 13), the async keyword interprets that as completing the Task<int> that was already constructed.
I have an async intro on my blog that you may find helpful.
The compiler is generating a Task for you that represents the entire asynchronous operation.
You have 3 options for async methods:
async void - This should be avoided in all cases other than event handlers
async Task - Here you have no control of the returned task, and it will be completed when the whole operation has ended (or when an exception is thrown) no matter how many awaits you have in it.
async Task<T> - This allows to actually return a value but behaves just the same as async Task.

What's the best way to wrap a Task as a Task<TResult>

I am writing some async helper methods and I have APIs to support both Task and Task<T>. To re-use code, I'd like the Task-based API to wrap the given task as a Task<T> and just call through to the Task<T> API.
One way I can do this is:
private static async Task<bool> Convert(this Task #this)
{
await #this.ConfigureAwait(false);
return false;
}
However, I'm wondering: is there there is a better/builtin way to do this?
There is no existing Task method that does exactly this, no. Your method is fine, and is likely about as simple as you'll be able to get.
Implementing the proper error propagating/cancellation semantics using any other method is deceptively hard.
Updated, the following propagates exceptions and cancellation:
public static class TaskExt
{
public static Task<Empty> AsGeneric(this Task #this)
{
return #this.IsCompleted ?
CompletedAsGeneric(#this) :
#this.ContinueWith<Task<Empty>>(CompletedAsGeneric,
TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
static Task<Empty> CompletedAsGeneric(Task completedTask)
{
try
{
if (completedTask.Status != TaskStatus.RanToCompletion)
// propagate exceptions
completedTask.GetAwaiter().GetResult();
// return completed task
return Task.FromResult(Empty.Value);
}
catch (OperationCanceledException ex)
{
// propagate cancellation
if (completedTask.IsCanceled)
// return cancelled task
return new Task<Empty>(() => Empty.Value, ex.CancellationToken);
throw;
}
}
}
public struct Empty
{
public static readonly Empty Value = default(Empty);
}
I've had the same requirement recently and I solved it with my own helper extension method, which allows the user to effectively wrap a Task with a Task<T>:
public static async Task<TResult> WithCompletionResult<TResult>(
this Task sourceTask,
TResult result
)
{
await sourceTask;
return result;
}
In your example call with:
Task<bool> task = myTask.WithCompletionResult<bool>(false);
If the result of Task<T> does not matter, I will use:
Task<object> task = myTask.WithCompletionResult<object>(null);
I hope this helps. If anyone knows of a pitfall with this approach let me know!
Using await seems a bit overkill here. No need for the state machine here, just use a ContinueWith
private static Task<bool> Convert(this Task #this)
{
return #this.ContinueWith(p => { p.Wait(); return false;});
}
Note: This will result in an AggregateException being wrapped unfortunately

async Indexer in C#

Recently, we have movied to EF 6 and we have begun to use EF async commands.
For example in my repository I have the following method:
// Gets entities asynchron in a range starting from skip.
// Take defines the maximum number of entities to be returned.
public async Task<IEnumerable<TEntity>> GetRangeAsync(int skip, int take)
{
var entities = this.AddIncludes(this.DbContext.Set<TEntity>())
.OrderBy(this.SortSpec.PropertyName)
.Skip(skip)
.Take(take)
.ToListAsync();
return await entities;
}
Now I have to modfiy the UI for the async data retrieving.
Below is my UI class; This class is bound to WPF.
public sealed class RepositoryCollectionView<TEntity, TEntityViewModel> : IList<TEntityViewModel>,
ICollectionView,
IEditableCollectionView,
IComparer
...
public TEntityViewModel this[int index]
{
get
{
return await this.GetItem(index).Result;
}
set
{
throw new NotSupportedException();
}
}
...
...
...
The problem: In the UI I have create a new method which called GetItemAsync(index) and I need to call this method from the Indexer;
When I write the keyword async to the indexer like that:
public async TEntityViewModel this[int index] I get the following error "The modfier 'async' is not valid for this item"
Any idea? any help would be greatly appreciated!
You simply can't make indexers async. From section 10.15 of the C# 5 specification:
A method or anonymous function with the async modifier is called an async function.
async is listed as one of the valid modifiers for methods (section 10.6), but not for indexers (10.9).
Bear in mind that an async method can only return void, Task and Task<T> - but you wouldn't want a setter to accept a Task<T> or Task, so what would the property type usefully be? (And why even have a setter if you're not supporting it?)
Given that it sound like a caller can already use GetItem - which should be GetItemAsync if it's returning a Task<TEntityViewModel> - I don't see that an indexer is going to help you.
You technically can't make indexers async. You can however have a get indexer return a Task or return the Task from an async method. Which accomplishes the same.
public class AsyncIndexer
{
public Task<int> this[int i] => GetValue(i);
public Task<string> this[string s] => Task.Run(async () =>
{
await Task.Delay(3000);
return s;
});
private async Task<int> GetValue(int i)
{
await Task.Delay(3000);
return i;
}
}
class Program
{
static void Main(string[] args)
{
Task.Run(async () =>
{
var asyncIndexer = new AsyncIndexer();
Console.WriteLine(await asyncIndexer[2]);
}).Wait();
}
}
Unfortunately setters can't return anything, so async setters are in no way possible because the await statement needs a task to be returned.
Could you imagine the syntax?
await (asyncIndexer[2] = 2)
I'd love that :p
This isn't possible properties cannot be async. Source
What you can do is call an asyncrounous method and wait for it to complete, but it will block (no async means no await).

Categories

Resources