in src/Microsoft.VisualStudio.Threading/CancellationTokenExtensions.cs [43:128]
public static CombinedCancellationToken CombineWith(this CancellationToken original, params CancellationToken[] others)
{
Requires.NotNull(others, nameof(others));
if (original.IsCancellationRequested)
{
return new CombinedCancellationToken(original);
}
int cancelableTokensCount = original.CanBeCanceled ? 1 : 0;
foreach (CancellationToken other in others)
{
if (other.IsCancellationRequested)
{
return new CombinedCancellationToken(other);
}
if (other.CanBeCanceled)
{
cancelableTokensCount++;
}
}
switch (cancelableTokensCount)
{
case 0:
return new CombinedCancellationToken(CancellationToken.None);
case 1:
if (original.CanBeCanceled)
{
return new CombinedCancellationToken(original);
}
foreach (CancellationToken other in others)
{
if (other.CanBeCanceled)
{
return new CombinedCancellationToken(other);
}
}
throw Assumes.NotReachable();
case 2:
CancellationToken first = CancellationToken.None;
CancellationToken second = CancellationToken.None;
if (original.CanBeCanceled)
{
first = original;
}
foreach (CancellationToken other in others)
{
if (other.CanBeCanceled)
{
if (first.CanBeCanceled)
{
second = other;
}
else
{
first = other;
}
}
}
Assumes.True(first.CanBeCanceled && second.CanBeCanceled);
// Call the overload that takes two CancellationTokens explicitly to avoid an array allocation.
return new CombinedCancellationToken(CancellationTokenSource.CreateLinkedTokenSource(first, second));
default:
// This is the most expensive path to take since it involves allocating memory and requiring disposal.
// Before this point we've checked every condition that would allow us to avoid it.
var cancelableTokens = new CancellationToken[cancelableTokensCount];
int i = 0;
foreach (CancellationToken other in others)
{
if (other.CanBeCanceled)
{
cancelableTokens[i++] = other;
}
}
return new CombinedCancellationToken(CancellationTokenSource.CreateLinkedTokenSource(cancelableTokens));
}
}