How to use PeriodicTimer inside of constructor?

Viewed 1232

I wanna start PeriodicTimer which is released in .NET 6, from constructor and in this timer i wanna update data with async method, how can I deal with it?

1 Answers

You can create an async method that calls this method and call it from whatever code you want to start the timer. You can call that method in the constructor itself and store the task it returns without awaiting it:

For example :

class MyClass:IDisposable:IAsyncDisposable
{

    PeriodicTimer _timer;
    Task _timerTask;
    CancellationTokenSource _cts;

    public MyClass()
    {
        _cts=new CancellationTokenSource();
        
        _timer=new PeriodicTimer(TimeSpan.FromSeconds(1));
        _timerTask=HandleTimerAsync(_timer,_cts.Token);
    }

    public void Cancel()=>_cts.Cancel();

    async Task HandleTimerAsync(PeriodicTimer timer,CancellationToken cancel=default)
    {
        try
        {
            while(await timer.WaitForNextTickAsync(cancel))
            {
                await Task.Run(()=>SomeHeavyJob(cancel),cancel);
            }
        }
        catch(Exception exc)
        {
            //Handle the exception but don't propagate it
        }

    }

    public async ValueTask DisposeAsync()
    {
        _timer.Dispose();
        await _timerTask;
        GC.SuppressFinalize(this);
    }


}

The reason for the complex disposal is that the timer task may not finish immediately after calling PeriodicTimer.Dispose(). The code will have to wait for it to complete..NET 6 introduced DisposeAsync for such cases.

Dispose and DisposeAsync methods shouldn't throw, which is why the handler method uses a catch block that doesn't propagate exceptions. Otherwise any expections thrown inside the handler would be rethrown in DisposeAsync, a place where handling or logging may not be possible because other objects are disposed themselves.

Related