I have a method LoopAsync
that takes a lambda parameter, and invokes this lambda repeatedly a number of times with a delay. Both the method and the lambda are asynchronous:
static async Task LoopAsync(Func<int, Task> action,
int start, int count, int delayMsec)
{
for (int i = start; i < start count; i )
{
await Task.Delay(delayMsec).ConfigureAwait(false);
await action(i).ConfigureAwait(false);
}
}
Now I want to enhance the LoopAsync
with an overload that takes a synchronous lambda parameter (an Action<int>
). I want to avoid duplicating my code, so I am thinking to implement the overload using the existing implementation like this:
static Task LoopAsync(Action<int> action,
int start, int count, int delayMsec)
{
return LoopAsync(i =>
{
action(i); return Task.CompletedTask;
}, start, count, delayMsec);
}
What I dislike with this approach is that it captures the action
argument, resulting in an allocation of an object every time the LoopAsync
is invoked. I want to prevent this capturing from happening. Is it possible?
To summarize, I want to have two method overloads, the first with asynchronous lambda and the second with synchronous lambda, that are sharing the same implementation, without incurring the penalty of allocating closure objects on the heap. I am equally OK with the one overload being based on the other, or with both being based on the same private
core implementation.
This question was inspired by a
According to my measurements, this optimization prevents the allocation of 88 bytes on the heap for each LoopAsync
invocation (.NET 6, Release built).