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); 
2

5 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) 
7

You 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(""); } } 
3

I 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() { } 
8

If 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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.