Finally.cs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace System.Linq
  10. {
  11. public static partial class AsyncEnumerable
  12. {
  13. public static IAsyncEnumerable<TSource> Finally<TSource>(this IAsyncEnumerable<TSource> source, Action finallyAction)
  14. {
  15. if (source == null)
  16. throw new ArgumentNullException(nameof(source));
  17. if (finallyAction == null)
  18. throw new ArgumentNullException(nameof(finallyAction));
  19. return new FinallyAsyncIterator<TSource>(source, finallyAction);
  20. }
  21. private sealed class FinallyAsyncIterator<TSource> : AsyncIterator<TSource>
  22. {
  23. private readonly Action finallyAction;
  24. private readonly IAsyncEnumerable<TSource> source;
  25. private IAsyncEnumerator<TSource> enumerator;
  26. public FinallyAsyncIterator(IAsyncEnumerable<TSource> source, Action finallyAction)
  27. {
  28. this.source = source;
  29. this.finallyAction = finallyAction;
  30. }
  31. public override AsyncIterator<TSource> Clone()
  32. {
  33. return new FinallyAsyncIterator<TSource>(source, finallyAction);
  34. }
  35. public override void Dispose()
  36. {
  37. if (enumerator != null)
  38. {
  39. enumerator.Dispose();
  40. enumerator = null;
  41. finallyAction();
  42. }
  43. base.Dispose();
  44. }
  45. protected override async Task<bool> MoveNextCore(CancellationToken cancellationToken)
  46. {
  47. switch (state)
  48. {
  49. case AsyncIteratorState.Allocated:
  50. enumerator = source.GetEnumerator();
  51. state = AsyncIteratorState.Iterating;
  52. goto case AsyncIteratorState.Iterating;
  53. case AsyncIteratorState.Iterating:
  54. if (await enumerator.MoveNext(cancellationToken)
  55. .ConfigureAwait(false))
  56. {
  57. current = enumerator.Current;
  58. return true;
  59. }
  60. Dispose();
  61. break;
  62. }
  63. return false;
  64. }
  65. }
  66. }
  67. }