コード例 #1
0
        private IAsyncEnumerable <int> TestProducer()
        {
            var queue = new UnicastAsyncEnumerable <int>();

            Handle();

            return(queue);

            async void Handle()
            {
                try
                {
                    for (int i = 0; i < 10; i++)
                    {
                        await Task.Delay(10);

                        await queue.Next(i);
                    }
                }
                finally
                {
                    await queue.Complete();
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Merges elements from all inner async-enumerable sequences concurrently into a single async-enumerable sequence.
        /// All thrown Exception are thrown at the end of the enumeration of all streams. Multiple Exceptions are thrown as AggregateException.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the source sequences.</typeparam>
        /// <param name="sources">Observable sequence of inner async-enumerable sequences.</param>
        /// <param name="cancellationToken">Cancellation Token to cancel the enumeration</param>
        /// <returns>The async-enumerable sequence that merges the elements of the inner sequences.</returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="sources" /> is null.</exception>
        public static IAsyncEnumerable <T> MergeConcurrently <T>(this IAsyncEnumerable <IAsyncEnumerable <T> > sources, CancellationToken cancellationToken = default)
        {
            var       queue           = new UnicastAsyncEnumerable <T>();
            var       tasks           = new List <Task>();
            Exception thrownException = null;

            StreamSources();

            return(queue);

            async void StreamSources()
            {
                try
                {
                    await foreach (var stream in sources.WithCancellation(cancellationToken))
                    {
                        tasks.Add(StreamSource(stream));
                    }

                    // After the last stream arrived, we have to wait until all of those streams have completely finished with streaming
                    await Task.WhenAll(tasks);

                    if (thrownException != null)
                    {
                        await queue.Error(thrownException);
                    }
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception e)
                {
                    ExceptionHelper.AddException(ref thrownException, e);
                    await queue.Error(thrownException);
                }
                finally
                {
                    await queue.Complete();
                }
            }

            async Task StreamSource(IAsyncEnumerable <T> source)
            {
                try
                {
                    await foreach (var item in source.WithCancellation(cancellationToken))
                    {
                        await queue.Next(item);
                    }
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception e)
                {
                    ExceptionHelper.AddException(ref thrownException, e);;
                }
            }
        }
コード例 #3
0
        public static async IAsyncEnumerable <T> If <T>(this IAsyncEnumerable <T> source, Func <T, bool> ifSelector,
                                                        Func <IAsyncEnumerable <T>, IAsyncEnumerable <T> > ifFunction, Func <IAsyncEnumerable <T>, IAsyncEnumerable <T> > elseFunction = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            var ifSourceStream   = new UnicastAsyncEnumerable <T>();
            var elseSourceStream = new UnicastAsyncEnumerable <T>();
            var ifResultStream   = ifFunction(ifSourceStream);
            var elseResultStream = elseFunction?.Invoke(elseSourceStream) ?? elseSourceStream;

            HandleStream();

            var result = ifResultStream.MergeConcurrently(elseResultStream);

            try
            {
                await foreach (var item in result.WithCancellation(cancellationToken))
                {
                    yield return(item);
                }
            }
            finally
            {
                await ifSourceStream.Complete();

                await elseSourceStream.Complete();
            }


            async void HandleStream()
            {
                try
                {
                    await foreach (var item in source.WithCancellation(cancellationToken))
                    {
                        if (ifSelector(item))
                        {
                            await ifSourceStream.Next(item);
                        }
                        else
                        {
                            await elseSourceStream.Next(item);
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception e)
                {
                    await elseSourceStream.Error(e);
                }
                finally
                {
                    await ifSourceStream.Complete();

                    await elseSourceStream.Complete();
                }
            }
        }
コード例 #4
0
        public async void Offline_Error()
        {
            var push = new UnicastAsyncEnumerable <int>();

            for (var i = 1; i <= 5; i++)
            {
                await push.Next(i);
            }
            await push.Error(new InvalidOperationException());

            await push.AssertFailure(typeof(InvalidOperationException), 1, 2, 3, 4, 5);
        }
コード例 #5
0
        public async void Complete_After_Dispose()
        {
            var push = new UnicastAsyncEnumerable <int>();

            var t = push.Take(1).AssertResult(1);

            await push.Next(1);

            await t;

            await push.Complete();
        }
コード例 #6
0
        public async void Error_After_Dispose()
        {
            var push = new UnicastAsyncEnumerable <int>();

            var t = push.Take(1).AssertResult(1);

            await push.Next(1);

            await t;

            await push.Error(new InvalidOperationException());
        }
コード例 #7
0
        /// <summary>
        /// Merges elements from all inner async-enumerable sequences concurrently into a single async-enumerable sequence.
        /// Enumeration stops on first thrown Exception of any inner streams.
        /// </summary>
        /// <typeparam name="T">The type of the elements in the source sequences.</typeparam>
        /// <param name="sources">Observable sequence of inner async-enumerable sequences.</param>
        /// <returns>The async-enumerable sequence that merges the elements of the inner sequences.</returns>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="sources" /> is null.</exception>
        public static IAsyncEnumerable <T> MergeConcurrentlyUntilFirstException <T>(this IAsyncEnumerable <IAsyncEnumerable <T> > sources)
        {
            var queue = new UnicastAsyncEnumerable <T>();
            var tasks = new List <Task>();

            StreamSources();

            return(queue);

            async void StreamSources()
            {
                try
                {
                    await foreach (var stream in sources)
                    {
                        tasks.Add(StreamSource(stream));
                    }

                    // After the last stream arrived, we have to wait until all of those streams have completely finished with streaming
                    await Task.WhenAll(tasks);
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception e)
                {
                    await queue.Error(e);
                }
                finally
                {
                    await queue.Complete();
                }
            }

            async Task StreamSource(IAsyncEnumerable <T> source)
            {
                try
                {
                    await foreach (var item in source)
                    {
                        await queue.Next(item);
                    }
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception e)
                {
                    await queue.Error(e);
                }
            }
        }
コード例 #8
0
        public async void Call_After_Done_2()
        {
            var push = new UnicastAsyncEnumerable <int>();
            await push.Error(new InvalidOperationException());

            await push.Complete();

            await push.Next(1);

            await push.Error(new IndexOutOfRangeException());

            await push.AssertFailure(typeof(InvalidOperationException));
        }
コード例 #9
0
        public async void Call_After_Done()
        {
            var push = new UnicastAsyncEnumerable <int>();
            await push.Complete();

            await push.Error(new InvalidOperationException());

            await push.Next(1);

            await push.Complete();

            await push.AssertResult();
        }
コード例 #10
0
        public async void One_Consumer_Only()
        {
            var push = new UnicastAsyncEnumerable <int>();

            var t = push.AssertResult();

            await push.AssertFailure(typeof(InvalidOperationException));

            await push.AssertFailure(typeof(InvalidOperationException));

            await push.Complete();

            await t;
        }
コード例 #11
0
        public async void Cancel()
        {
            var cts = new CancellationTokenSource();

            var push = new UnicastAsyncEnumerable <long>();

            var t = AsyncEnum.Timer(TimeSpan.FromMilliseconds(500))
                    .Consume(push, cts.Token);

            await Task.Delay(100, cts.Token);

            cts.Cancel();

            await t;
        }
コード例 #12
0
        public async void Next_After_Dispose()
        {
            var push = new UnicastAsyncEnumerable <int>();

            var t = push.Take(1).AssertResult(1);

            Assert.True(push.HasConsumers);
            Assert.False(push.IsDisposed);

            await push.Next(1);

            await t;

            Assert.False(push.HasConsumers);
            Assert.True(push.IsDisposed);

            await push.Next(2);
        }
コード例 #13
0
        public async void Offline()
        {
            var push = new UnicastAsyncEnumerable <int>();

            Assert.False(push.HasConsumers);
            Assert.False(push.IsDisposed);

            for (var i = 1; i <= 5; i++)
            {
                await push.Next(i);
            }
            await push.Complete();

            await push.AssertResult(1, 2, 3, 4, 5);

            Assert.False(push.HasConsumers);
            Assert.True(push.IsDisposed);
        }