From f154e3624f9a3a452438755f876990eeb649d7af Mon Sep 17 00:00:00 2001 From: forest93 Date: Sat, 14 Oct 2017 20:44:24 +0800 Subject: [PATCH] AsyncEnumerableBuffer throws ObjectDisposedException for access after disposal. Add docs. --- .../AsyncEnumerableExtensions.csproj | 3 +- .../AsyncEnumerableFactory.cs | 30 +++++++++++++++++++ .../IAsyncEnumerableSink.cs | 2 +- .../TaskAsyncEnumerable.cs | 18 +++++------ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/AsyncEnumerableExtensions/AsyncEnumerableExtensions.csproj b/AsyncEnumerableExtensions/AsyncEnumerableExtensions.csproj index 7b87dd1..2550971 100644 --- a/AsyncEnumerableExtensions/AsyncEnumerableExtensions.csproj +++ b/AsyncEnumerableExtensions/AsyncEnumerableExtensions.csproj @@ -4,7 +4,7 @@ netstandard1.1 CXuesong.AsyncEnumerableExtensions CXuesong - 0.1.3 + 0.1.4 Some rudimentary utilities to flavor Ix.Async. Such as asynchronous generator methods. https://github.com/CXuesong/AsyncEnumerableExtensions git @@ -12,6 +12,7 @@ https://github.com/CXuesong/AsyncEnumerableExtensions/blob/master/LICENSE.txt https://github.com/CXuesong/AsyncEnumerableExtensions true + True true ../AsyncEnumerableExtensions.snk diff --git a/AsyncEnumerableExtensions/AsyncEnumerableFactory.cs b/AsyncEnumerableExtensions/AsyncEnumerableFactory.cs index 6b6d101..0c4585b 100644 --- a/AsyncEnumerableExtensions/AsyncEnumerableFactory.cs +++ b/AsyncEnumerableExtensions/AsyncEnumerableFactory.cs @@ -12,13 +12,43 @@ namespace AsyncEnumerableExtensions public static class AsyncEnumerableFactory { + /// + /// Creates an instance of from an asynchronous generator method. + /// + /// Type of the items. + /// Generator method. + /// The encapsulated . + /// + /// The parameter should use + /// passed in to yield the items. + /// In this overload, the asynchronous generator accepts a + /// which is cancelled when the is disposed. + /// + /// + /// + /// public static IAsyncEnumerable FromAsyncGenerator(Func, CancellationToken, Task> generator) { + if (generator == null) throw new ArgumentNullException(nameof(generator)); return new TaskAsyncEnumerable(generator); } + /// + /// Creates an instance of from an asynchronous generator method. + /// + /// Type of the items. + /// Generator method. + /// The encapsulated . + /// + /// The parameter should use + /// passed in to yield the items. + /// + /// + /// + /// public static IAsyncEnumerable FromAsyncGenerator(Func, Task> generator) { + if (generator == null) throw new ArgumentNullException(nameof(generator)); return new TaskAsyncEnumerable(generator); } diff --git a/AsyncEnumerableExtensions/IAsyncEnumerableSink.cs b/AsyncEnumerableExtensions/IAsyncEnumerableSink.cs index a8961be..ef7ba87 100644 --- a/AsyncEnumerableExtensions/IAsyncEnumerableSink.cs +++ b/AsyncEnumerableExtensions/IAsyncEnumerableSink.cs @@ -32,7 +32,7 @@ public interface IAsyncEnumerableSink /// The token used to cancel waiting. /// A task that completes when the yielded item has been consumed. /// The wait operation has been cancelled. - /// The sink does not accepts items anymore. + /// The sink does not accept items anymore. Task Wait(CancellationToken cancellationToken); } diff --git a/AsyncEnumerableExtensions/TaskAsyncEnumerable.cs b/AsyncEnumerableExtensions/TaskAsyncEnumerable.cs index 42455d0..7f6ebc3 100644 --- a/AsyncEnumerableExtensions/TaskAsyncEnumerable.cs +++ b/AsyncEnumerableExtensions/TaskAsyncEnumerable.cs @@ -8,29 +8,26 @@ namespace AsyncEnumerableExtensions { - public class TaskAsyncEnumerable : IAsyncEnumerable + internal class TaskAsyncEnumerable : IAsyncEnumerable { private readonly Func, CancellationToken, Task> generator; - private readonly bool acceptsCancellationToken; public TaskAsyncEnumerable(Func, Task> sourceTask) { if (sourceTask == null) throw new ArgumentNullException(nameof(sourceTask)); generator = (sink, ct) => sourceTask(sink); - acceptsCancellationToken = false; } public TaskAsyncEnumerable(Func, CancellationToken, Task> sourceTask) { this.generator = sourceTask ?? throw new ArgumentNullException(nameof(sourceTask)); - acceptsCancellationToken = true; } /// public IAsyncEnumerator GetEnumerator() { - return new Enumerator(generator, acceptsCancellationToken); + return new Enumerator(generator); } private class Enumerator : IAsyncEnumerator @@ -43,7 +40,7 @@ private class Enumerator : IAsyncEnumerator private CancellationToken lastMoveNextCancellationToken = CancellationToken.None; private CancellationTokenSource lastCombinedCancellationTokenSource; - public Enumerator(Func, CancellationToken, Task> generator, bool acceptsCancellationToken) + public Enumerator(Func, CancellationToken, Task> generator) { Debug.Assert(generator != null); this.generator = generator; @@ -188,10 +185,11 @@ public bool Yield(IEnumerable items) public Task Wait(CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); + if (cancellationToken.IsCancellationRequested) + return Task.Delay(-1, cancellationToken); lock (syncLock) { - if (queue == null) throw new ObjectDisposedException(nameof(AsyncEnumerableBuffer)); + if (queue == null) return ObjectDisposedTask; if (queue.Count == 0) return CompletedTask; if (onQueueExhaustedTcs == null) { @@ -249,8 +247,8 @@ internal void Terminate() { lock (syncLock) { - onQueueExhaustedTcs?.TrySetCanceled(); - onYieldTcs?.TrySetCanceled(); + onQueueExhaustedTcs?.TrySetException(new ObjectDisposedException(nameof(AsyncEnumerableBuffer))); + onYieldTcs?.TrySetException(new ObjectDisposedException(nameof(AsyncEnumerableBuffer))); onQueueExhaustedTcs = null; onYieldTcs = null; queue = null;