Saturday, November 15, 2014

AutoCancellationTokenSource

With the following code you can create a CancellationTokenSource that will signal cancellation on dispose. This provides an alternative to having to wrap a normal CancellationTokenSource in a try finally block.

Code

public class AutoCancellationTokenSource : CancellationTokenSource
{
    private bool _isDisposed;
 
    public AutoCancellationTokenSource()
    {
    }
 
    public AutoCancellationTokenSource(params CancellationToken[] linkedTokens)
    {
        foreach (var linkedToken in linkedTokens)
            if (linkedToken.IsCancellationRequested)
                TryCancel();
            else
                linkedToken.Register(TryCancel, false);
    }
 
    protected override void Dispose(bool disposing)
    {
        if (_isDisposed)
            return;
 
        TryCancel();
 
        base.Dispose(disposing);
 
        _isDisposed = true;
    }
 
    private void TryCancel()
    {
        if (!_isDisposed && !IsCancellationRequested)
            Cancel();
    }
}

Tests

public class AutoCancellationTokenSourceTests
{
    [Fact]
    public void StandardTest()
    {
        CancellationToken token;
 
        using (var source = new CancellationTokenSource())
            token = source.Token;
 
        Assert.False(token.IsCancellationRequested);
    }
 
    [Fact]
    public void AutoTest()
    {
        CancellationToken token;
 
        using (var source = new AutoCancellationTokenSource())
            token = source.Token;
 
        Assert.True(token.IsCancellationRequested);
    }
 
    [Fact]
    public void LinkedTest()
    {
        using (var standardSource = new CancellationTokenSource())
        using (var autoSource = new AutoCancellationTokenSource(
            standardSource.Token))
        {
            Assert.False(autoSource.IsCancellationRequested);
            standardSource.Cancel();
            Assert.True(autoSource.IsCancellationRequested);
        }
    }
 
    [Fact]
    public void LinkedPreCancelTest()
    {
        using (var standardSource = new CancellationTokenSource())
        {
            standardSource.Cancel();
 
            using (var autoSource = new AutoCancellationTokenSource(
                standardSource.Token))
            {
                Assert.True(autoSource.IsCancellationRequested);
            }
        }
    }
 
    [Fact]
    public void MultipleLinkedTest()
    {
        using (var standardSource1 = new CancellationTokenSource())
        using (var standardSource2 = new CancellationTokenSource())
        using (var autoSource = new AutoCancellationTokenSource(
            standardSource1.Token, 
            standardSource2.Token))
        {
            Assert.False(autoSource.IsCancellationRequested);
            standardSource1.Cancel();
            Assert.True(autoSource.IsCancellationRequested);
            standardSource2.Cancel();
            Assert.True(autoSource.IsCancellationRequested);
        }
    }
}

Enjoy,
Tom

No comments:

Post a Comment

Real Time Web Analytics