You're on the right track. However, I would suggest waiting for the task to terminate before returning from the Dispose
method, in order to avoid race conditions where the task continues to operate after the object has been disposed. Also dispose the CancellationTokenSource
.
Update: If you're on .NET Core 3.0 or later, you should make your class implement IAsyncDisposable
and await your task from the DisposeAsyncCore
method. I've updated the example below to reflect this.
using System;
using System.Threading;
using System.Threading.Tasks;
public class MyClass : IDisposable, IAsyncDisposable
{
private readonly CancellationTokenSource feedCancellationTokenSource =
new CancellationTokenSource();
private readonly Task feedTask;
public MyClass()
{
feedTask = Task.Factory.StartNew(() =>
{
while (!feedCancellationTokenSource.IsCancellationRequested)
{
// do finite work
}
});
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
feedCancellationTokenSource.Cancel();
feedTask.Wait();
feedCancellationTokenSource.Dispose();
feedTask.Dispose();
}
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
protected virtual async ValueTask DisposeAsyncCore()
{
feedCancellationTokenSource.Cancel();
await feedTask.ConfigureAwait(false);
feedCancellationTokenSource.Dispose();
feedTask.Dispose();
}
}
// Sample usage:
public static class Program
{
public static async Task Main()
{
await using (new MyClass())
{
// do something else
}
Console.WriteLine("Done");
}
}