AsyncIterator.cs 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. internal abstract partial class AsyncIterator<TSource> : IAsyncEnumerable<TSource>, IAsyncEnumerator<TSource>
  10. {
  11. private readonly int _threadId;
  12. protected TSource _current;
  13. protected AsyncIteratorState _state = AsyncIteratorState.New;
  14. protected CancellationToken _cancellationToken;
  15. protected AsyncIterator()
  16. {
  17. _threadId = Environment.CurrentManagedThreadId;
  18. }
  19. public IAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken)
  20. {
  21. var enumerator = _state == AsyncIteratorState.New && _threadId == Environment.CurrentManagedThreadId
  22. ? this
  23. : Clone();
  24. enumerator._state = AsyncIteratorState.Allocated;
  25. enumerator._cancellationToken = cancellationToken;
  26. return enumerator;
  27. }
  28. public virtual ValueTask DisposeAsync()
  29. {
  30. _current = default;
  31. _state = AsyncIteratorState.Disposed;
  32. return TaskExt.CompletedTask;
  33. }
  34. public TSource Current => _current;
  35. public async ValueTask<bool> MoveNextAsync()
  36. {
  37. // Note: MoveNext *must* be implemented as an async method to ensure
  38. // that any exceptions thrown from the MoveNextCore call are handled
  39. // by the try/catch, whether they're sync or async
  40. if (_state == AsyncIteratorState.Disposed)
  41. {
  42. return false;
  43. }
  44. try
  45. {
  46. return await MoveNextCore().ConfigureAwait(false);
  47. }
  48. catch
  49. {
  50. await DisposeAsync().ConfigureAwait(false);
  51. throw;
  52. }
  53. }
  54. public abstract AsyncIterator<TSource> Clone();
  55. protected abstract ValueTask<bool> MoveNextCore();
  56. }
  57. internal enum AsyncIteratorState
  58. {
  59. New = 0,
  60. Allocated = 1,
  61. Iterating = 2,
  62. Disposed = -1,
  63. }
  64. }