I have async callback, which is passed into Timer(from System.Threading) constructor :
private async Task HandleTimerCallback(object state) { if (timer == null) return; if (asynTaskCallback != null) { await HandleAsyncTaskTimerCallback(state); } else { HandleSyncTimerCallback(state); } } And Timer :
timer = new Timer(async o => await HandleTimerCallback(o), state, CommonConstants.InfiniteTimespan, CommonConstants.InfiniteTimespan); Is there any way to omit that o param in lambda? Cause for not-async I can just pass my handler as delegate
timer = new Timer(HandleTimerCallback, state, CommonConstants.InfiniteTimespan, CommonConstants.InfiniteTimespan); 25 Answers
Is there any way to omit that o param in lambda?
Sure, just define your event handler method as async void:
private async void HandleTimerCallback(object state) 7You could use a wrapper method, as recommended by David Fowler here:
public class Pinger { private readonly Timer _timer; private readonly HttpClient _client; public Pinger(HttpClient client) { _client = client; _timer = new Timer(Heartbeat, null, 1000, 1000); } public void Heartbeat(object state) { // Discard the result _ = DoAsyncPing(); } private async Task DoAsyncPing() { await _client.GetAsync(""); } } 3I just wanted to mention that .NET 6 introduced a new timer class called PeriodicTimer that is async-first and avoids callbacks altogether.
Usage looks somewhat weird at first (because it's an endless loop), but since it's async, it does not block execution of other threads:
public async Task DoStuffPeriodically() { var timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); while (await timer.WaitForNextTickAsync()) { //do stuff } } It avoids callbacks altogether, uses simpler code and is a perfect candidate for background services.
You basically get a "never ending task" that does stuff.
To start the task simply call, for example _ = DoStuffPeriodically() with a discard operator (but do add try-catch inside the method so the background task does not crash) or launch this task via Task.Run
Nick Chapsas has a nice video explaining the usage: (including how to use a CancellationToken to abort the timer).
I used a wrapper like Vlad suggested above but then used a Task.Wait so that the asynchronous process completes:
private void ProcessWork(object state) { Task.WaitAll(ProcessScheduledWorkAsync()); } protected async Task ProcessWorkAsync() { } 8If you don't want a wrapper class, you can do this in your TimerCallback function:
private void TimerFunction(object state) { _ = Task.Run(async () => { await this.SomeFunctionAsync().ConfigureAwait(false); }); } 1