I love that .NET has so many useful utilities available in the base framework. I often use the SemaphoreSlim, and I love that it supports async await. However, I don't like always having to create a try finally block around every use call to ensure that the release method gets called.
Below is a simple little extension method that will allow you to place the result of the Semaphore wait into a using block, thus ensuring that the dispose will always release the lock.
SemaphoreSlim Extensions
public static class SemaphoreSlimExtensions
{
public static async Task<IDisposable> UseWaitAsync(
this SemaphoreSlim semaphore,
CancellationToken cancelToken = default(CancellationToken))
{
await semaphore.WaitAsync(cancelToken).ConfigureAwait(false);
return new ReleaseWrapper(semaphore);
}
private class ReleaseWrapper : IDisposable
{
private readonly SemaphoreSlim _semaphore;
private bool _isDisposed;
public ReleaseWrapper(SemaphoreSlim semaphore)
{
_semaphore = semaphore;
}
public void Dispose()
{
if (_isDisposed)
return;
_semaphore.Release();
_isDisposed = true;
}
}
}