AsyncEnumerableExtensions.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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.Runtime.CompilerServices;
  6. namespace System.Threading.Tasks
  7. {
  8. public static class AsyncEnumerableExtensions
  9. {
  10. #if !BCL_HAS_CONFIGUREAWAIT // https://github.com/dotnet/coreclr/pull/21939
  11. /// <summary>Configures how awaits on the tasks returned from an async disposable will be performed.</summary>
  12. /// <param name="source">The source async disposable.</param>
  13. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  14. /// <returns>The configured async disposable.</returns>
  15. public static ConfiguredAsyncDisposable ConfigureAwait(this IAsyncDisposable source, bool continueOnCapturedContext) =>
  16. new ConfiguredAsyncDisposable(source, continueOnCapturedContext);
  17. /// <summary>Configures how awaits on the tasks returned from an async iteration will be performed.</summary>
  18. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  19. /// <param name="source">The source enumerable being iterated.</param>
  20. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  21. /// <returns>The configured enumerable.</returns>
  22. public static ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait<T>(
  23. this IAsyncEnumerable<T> source, bool continueOnCapturedContext) =>
  24. new ConfiguredCancelableAsyncEnumerable<T>(source, continueOnCapturedContext, cancellationToken: default);
  25. /// <summary>Sets the <see cref="CancellationToken"/> to be passed to <see cref="IAsyncEnumerable{T}.GetAsyncEnumerator(CancellationToken)"/> when iterating.</summary>
  26. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  27. /// <param name="source">The source enumerable being iterated.</param>
  28. /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
  29. /// <returns>The configured enumerable.</returns>
  30. public static ConfiguredCancelableAsyncEnumerable<T> WithCancellation<T>(
  31. this IAsyncEnumerable<T> source, CancellationToken cancellationToken) =>
  32. new ConfiguredCancelableAsyncEnumerable<T>(source, continueOnCapturedContext: true, cancellationToken);
  33. #elif !REFERENCE_ASSEMBLY
  34. // we need to carry an impl that delegates to the BCL version of these
  35. /// <summary>Configures how awaits on the tasks returned from an async disposable will be performed.</summary>
  36. /// <param name="source">The source async disposable.</param>
  37. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  38. /// <returns>The configured async disposable.</returns>
  39. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  40. public static ConfiguredAsyncDisposable ConfigureAwait(this IAsyncDisposable source, bool continueOnCapturedContext) =>
  41. TaskExtensions.ConfigureAwait(source, continueOnCapturedContext);
  42. /// <summary>Configures how awaits on the tasks returned from an async iteration will be performed.</summary>
  43. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  44. /// <param name="source">The source enumerable being iterated.</param>
  45. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  46. /// <returns>The configured enumerable.</returns>
  47. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  48. public static ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait<T>(
  49. this IAsyncEnumerable<T> source, bool continueOnCapturedContext) => TaskExtensions.ConfigureAwait(source, continueOnCapturedContext);
  50. /// <summary>Sets the <see cref="CancellationToken"/> to be passed to <see cref="IAsyncEnumerable{T}.GetAsyncEnumerator(CancellationToken)"/> when iterating.</summary>
  51. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  52. /// <param name="source">The source enumerable being iterated.</param>
  53. /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
  54. /// <returns>The configured enumerable.</returns>
  55. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  56. public static ConfiguredCancelableAsyncEnumerable<T> WithCancellation<T>(
  57. this IAsyncEnumerable<T> source, CancellationToken cancellationToken) => TaskExtensions.WithCancellation(source, cancellationToken);
  58. #else
  59. // Reference assembly, these won't be emitted, but keep these internal so we can compile
  60. /// <summary>Configures how awaits on the tasks returned from an async disposable will be performed.</summary>
  61. /// <param name="source">The source async disposable.</param>
  62. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  63. /// <returns>The configured async disposable.</returns>
  64. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  65. internal static ConfiguredAsyncDisposable ConfigureAwait(this IAsyncDisposable source, bool continueOnCapturedContext) =>
  66. TaskExtensions.ConfigureAwait(source, continueOnCapturedContext);
  67. /// <summary>Configures how awaits on the tasks returned from an async iteration will be performed.</summary>
  68. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  69. /// <param name="source">The source enumerable being iterated.</param>
  70. /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
  71. /// <returns>The configured enumerable.</returns>
  72. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  73. internal static ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait<T>(
  74. this IAsyncEnumerable<T> source, bool continueOnCapturedContext) => TaskExtensions.ConfigureAwait(source, continueOnCapturedContext);
  75. /// <summary>Sets the <see cref="CancellationToken"/> to be passed to <see cref="IAsyncEnumerable{T}.GetAsyncEnumerator(CancellationToken)"/> when iterating.</summary>
  76. /// <typeparam name="T">The type of the objects being iterated.</typeparam>
  77. /// <param name="source">The source enumerable being iterated.</param>
  78. /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
  79. /// <returns>The configured enumerable.</returns>
  80. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  81. internal static ConfiguredCancelableAsyncEnumerable<T> WithCancellation<T>(
  82. this IAsyncEnumerable<T> source, CancellationToken cancellationToken) => TaskExtensions.WithCancellation(source, cancellationToken);
  83. #endif
  84. public static ConfiguredCancelableAsyncEnumerable<T>.Enumerator GetConfiguredAsyncEnumerator<T>(this IAsyncEnumerable<T> enumerable, CancellationToken cancellationToken, bool continueOnCapturedContext)
  85. {
  86. #if REFERENCE_ASSEMBLY
  87. return default;
  88. #else
  89. return ConfigureAwait(enumerable, continueOnCapturedContext).WithCancellation(cancellationToken).GetAsyncEnumerator();
  90. #endif
  91. }
  92. }
  93. }