Использование CancellationToken
является решением, поскольку это единственное, что может отменить Task.Delay
в вашем коде.То, как мы получаем его в вашем IAsyncEnumerable
, это передаем его в качестве параметра при его создании, поэтому давайте сделаем это:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
await Task.Delay(1000, cancellationToken);
}
}
С потребляющей стороной:
// In this example the cancellation token will be caneled after 2.5 seconds
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2.5));
await foreach (var item in EnumerateAsync(cts.Token)) {
Console.WriteLine(item);
}
Конечно, это отменит перечисление после того, как были возвращены 3 элемента, но закончится TaskCanceledException
, выброшенным из Task.Delay
.Чтобы изящно выйти из await foreach
, мы должны поймать его и сломать на стороне производства:
public async IAsyncEnumerable<int> EnumerateAsync(CancellationToken cancellationToken = default) {
for (int i = 0; i < 10; i++) {
yield return i;
try {
await Task.Delay(1000, cancellationToken);
} catch (TaskCanceledException) {
yield break;
}
}
}
Примечание
На данный момент это все еще в предварительном просмотре и может быть изменено.Если вы заинтересованы в этой теме, вы можете посмотреть обсуждение языковой команды C # о CancellationToken
в IAsyncEnumeration
.