複数のキャンセル待ち

async/awaitで非同期のコードを書いているとCancellationTokenを良く使う。
複数のCancellationTokenを使う場合、「すべて」のキャンセルを待機するにはCancellationTokenSource#CreateLinkedTokenSource()を使えばいいらしいが、「いずれか」のキャンセルを待機する仕組みがないようなので作ってみた。


#2013/08/15追記
CancellationTokenSource#CreateLinkedTokenSource()は引数に指定した「いずれかの」Tokenのキャンセル待ちのために使用できます。
日本語のMSDNには一部「すべての」という記述がありますが誤訳と思われます。
英語のMSDNを確認してください。

public class MultiCancellationToken : IDisposable
{

private List<CancellationTokenRegistration> _cancellationTokenRegistrationList = new List<CancellationTokenRegistration>();
private CancellationTokenSource _cts = new CancellationTokenSource();
private bool _disposed;

public MultiCancellationToken(params CancellationToken[] tokens)
{
    foreach (var token in tokens)
    {
        _cancellationTokenRegistrationList.Add(token.Register(() => { Cancel(); }));
    }
}

private void Cancel()
{
    lock (this)
    {
        if (_cts.IsCancellationRequested)
        {
            return;
        }
        _cts.Cancel();
        foreach (var token in _cancellationTokenRegistrationList)
        {
            token.Dispose();
        }
        _cancellationTokenRegistrationList.Clear();
    }
}

public CancellationToken Token
{
    get { return _cts.Token; }
}

protected void Dispose(bool dispose)
{
    if (!dispose || _disposed)
    {
        return;
    }
    _disposed = true;
    lock (this)
    {
        foreach (var token in _cancellationTokenRegistrationList)
        {
            token.Dispose();
        }
        _cancellationTokenRegistrationList.Clear();
        _cts.Dispose();
    }
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

~MultiCancellationToken()
{
    Dispose(false);
}

}

c#のDisposeの流儀がいまいちわかってない・・・