Wrapping async methods in a synchronous part for parameter checks, as required by SonarQube code rule S4457, can quickly become hard to read. With C# local methods, the parameters can be omitted for the local method.
Does this omission of parameters have any disadvantages or issues with the compiler and local methods?
public Task<MyResult> GetMyResultAsync(string myId, string someOption, CancellationToken cancellationToken)
{
// check arguments synchronously, before entering async context:
myId = myId ?? throw new ArgumentNullException(nameof(myId));
someOption = someOption ?? throw new ArgumentNullException(nameof(someOption));
return InnerAsync();
// don't replicate the arguments, use from outer method.
async Task<MyResult> InnerAsync()
{
using var httpClient = _httpClientFactory.CreateClient(CfgName);
var response = await httpClient.GetAsync(
CreateUrl(myId, someOption), cancellationToken)
.ConfigureAwait(false);
return ParseResponse<MyResult>(response);
}
}
as compared to:
public Task<MyResult> GetMyResultAsync(string myId, string someOption, CancellationToken cancellationToken)
{
// check arguments synchronously, before entering async context:
myId = myId ?? throw new ArgumentNullException(nameof(myId));
someOption = someOption ?? throw new ArgumentNullException(nameof(someOption));
return InnerAsync(myId, someOption, cancellationToken);
// new arguments for inner async method:
async Task<MyResult> InnerAsync(
string myIdInner, string someOptionInner,
CancellationToken cancellationTokenInner)
{
using var httpClient = _httpClientFactory.CreateClient(CfgName);
var response = await httpClient.GetAsync(
CreateUrl(myIdInner, someOptionInner),
cancellationTokenInner)
.ConfigureAwait(false);
return ParseResponse<MyResult>(response);
}
}
Background: The rule requires parameter check, throwing Argument(Null/OutOfRange)Exception, to happen synchronously, before entering the async context, so that these exceptions don't get lost in case of fire-and-forget; they will be thrown before an async task is even created. The methods are still named "-Async", since they were before the rule was applied.
I know that async methods are basically compiled into state machines, with local variables as properties, so I wouldn't expect any disadvantage from using the outer variables. Correct?