AsyncEnumerableEx.cs 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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.Diagnostics;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerableEx
  10. {
  11. private static IAsyncEnumerator<T> CreateEnumerator<T>(Func<TaskCompletionSource<bool>, Task<bool>> moveNext, Func<T> current, Func<Task> dispose)
  12. {
  13. var self = new AnonymousAsyncIterator<T>(
  14. async () =>
  15. {
  16. var tcs = new TaskCompletionSource<bool>();
  17. return await moveNext(tcs).ConfigureAwait(false);
  18. },
  19. current,
  20. dispose
  21. );
  22. return self;
  23. }
  24. private sealed class AnonymousAsyncIterator<T> : AsyncIterator<T>
  25. {
  26. private readonly Func<T> currentFunc;
  27. private readonly Func<Task> dispose;
  28. private readonly Func<Task<bool>> moveNext;
  29. public AnonymousAsyncIterator(Func<Task<bool>> moveNext, Func<T> currentFunc, Func<Task> dispose)
  30. {
  31. Debug.Assert(moveNext != null);
  32. this.moveNext = moveNext;
  33. this.currentFunc = currentFunc;
  34. this.dispose = dispose;
  35. // Explicit call to initialize enumerator mode
  36. GetAsyncEnumerator();
  37. }
  38. public override AsyncIterator<T> Clone()
  39. {
  40. throw new NotSupportedException("AnonymousAsyncIterator cannot be cloned. It is only intended for use as an iterator.");
  41. }
  42. public override async Task DisposeAsync()
  43. {
  44. if (dispose != null)
  45. {
  46. await dispose().ConfigureAwait(false);
  47. }
  48. await base.DisposeAsync().ConfigureAwait(false);
  49. }
  50. protected override async Task<bool> MoveNextCore()
  51. {
  52. switch (state)
  53. {
  54. case AsyncIteratorState.Allocated:
  55. state = AsyncIteratorState.Iterating;
  56. goto case AsyncIteratorState.Iterating;
  57. case AsyncIteratorState.Iterating:
  58. if (await moveNext().ConfigureAwait(false))
  59. {
  60. current = currentFunc();
  61. return true;
  62. }
  63. await DisposeAsync().ConfigureAwait(false);
  64. break;
  65. }
  66. return false;
  67. }
  68. }
  69. }
  70. }