What are differences between the 3 calls inside method WhatDifferences
?
Here is test code:
async Task WhatDifferences(Context context)
{
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
}
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
return await action(context).ConfigureAwait(false);
}
async Task<bool> IsOddAsync(Context context)
{
return await Task.Run(() => context.Count++ % 2 == 1).ConfigureAwait(false);
}
class Context
{
public int Count { get; set; }
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
The question is different with What's the method signature for passing an async delegate?
You may know my concern if I show more logic
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
using (var transaction = new TransactionScope())
{
//do some async logic before action
var result = await action(context).ConfigureAwait(false);
//do other async validation logic after action
return result;
}
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
In this specific instance, this is essentially true.
This one creates a delegate that refers to the IsOddAsync
method:
await ActionAsync(context, IsOddAsync);
This one creates a method for the lambda expression and the delegate refers to that compiler-generated method:
await ActionAsync(context, x => IsOddAsync(x));
And this one does the same, but for an asynchronous lambda, so the compiler-generated method also has an async
state machine:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
In general, your question boils down to two questions:
async
/await
or keep the keywords in? This one is more nuanced.Eliding async
in this particular case is fine, because all the async
lambda is doing is calling a single method and passing its parameter. There's no possibility of exceptions being thrown from the lambda before or after the call to IsOddAsync
.
However, if your lambda is more complex - doing operations on x
before passing it to IsOddAsync
, or doing operations on the result, or using a using
block, then you'd want to keep the async
/await
keywords for maximum maintainability. More information here.