Finally.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT 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. public static partial class AsyncEnumerableEx
  10. {
  11. /// <summary>
  12. /// Invokes a specified action after the source async-enumerable sequence terminates gracefully or exceptionally.
  13. /// </summary>
  14. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  15. /// <param name="source">Source sequence.</param>
  16. /// <param name="finallyAction">Action to invoke after the source async-enumerable sequence terminates.</param>
  17. /// <returns>Source sequence with the action-invoking termination behavior applied.</returns>
  18. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="finallyAction"/> is null.</exception>
  19. public static IAsyncEnumerable<TSource> Finally<TSource>(this IAsyncEnumerable<TSource> source, Action finallyAction)
  20. {
  21. if (source == null)
  22. throw Error.ArgumentNull(nameof(source));
  23. if (finallyAction == null)
  24. throw Error.ArgumentNull(nameof(finallyAction));
  25. #if HAS_ASYNC_ENUMERABLE_CANCELLATION
  26. return Core(source, finallyAction);
  27. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Action finallyAction, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
  28. #else
  29. return AsyncEnumerable.Create(Core);
  30. async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
  31. #endif
  32. {
  33. try
  34. {
  35. await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  36. {
  37. yield return item;
  38. }
  39. }
  40. finally
  41. {
  42. finallyAction();
  43. }
  44. }
  45. }
  46. /// <summary>
  47. /// Invokes a specified asynchronous action after the source async-enumerable sequence terminates gracefully or exceptionally.
  48. /// </summary>
  49. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  50. /// <param name="source">Source sequence.</param>
  51. /// <param name="finallyAction">Action to invoke and await asynchronously after the source async-enumerable sequence terminates.</param>
  52. /// <returns>Source sequence with the action-invoking termination behavior applied.</returns>
  53. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="finallyAction"/> is null.</exception>
  54. public static IAsyncEnumerable<TSource> Finally<TSource>(this IAsyncEnumerable<TSource> source, Func<Task> finallyAction)
  55. {
  56. if (source == null)
  57. throw Error.ArgumentNull(nameof(source));
  58. if (finallyAction == null)
  59. throw Error.ArgumentNull(nameof(finallyAction));
  60. #if HAS_ASYNC_ENUMERABLE_CANCELLATION
  61. return Core(source, finallyAction);
  62. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<Task> finallyAction, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
  63. #else
  64. return AsyncEnumerable.Create(Core);
  65. async IAsyncEnumerator<TSource> Core(CancellationToken cancellationToken)
  66. #endif
  67. {
  68. try
  69. {
  70. await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  71. {
  72. yield return item;
  73. }
  74. }
  75. finally
  76. {
  77. // REVIEW: No cancellation support for finally action.
  78. await finallyAction().ConfigureAwait(false);
  79. }
  80. }
  81. }
  82. }
  83. }