OrderBy.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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 AsyncEnumerable
  10. {
  11. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  12. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.orderby?view=net-9.0-pp#system-linq-asyncenumerable-orderby-2(system-collections-generic-iasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  13. // The method linked to above includes a comparer parameter with a default value of null.
  14. /// <summary>
  15. /// Sorts the elements of a sequence in ascending order according to a key.
  16. /// </summary>
  17. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  18. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  19. /// <param name="source">An async-enumerable sequence of values to order.</param>
  20. /// <param name="keySelector">A function to extract a key from an element.</param>
  21. /// <returns>An ordered async-enumerable sequence whose elements are sorted according to a key.</returns>
  22. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  23. public static IOrderedAsyncEnumerable<TSource> OrderBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector) =>
  24. new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer: null, descending: false, parent: null);
  25. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  26. /// <summary>
  27. /// Sorts the elements of a sequence in ascending order according to a key obtained by invoking a transform function on each element and awaiting the result.
  28. /// </summary>
  29. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  30. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  31. /// <param name="source">An async-enumerable sequence of values to order.</param>
  32. /// <param name="keySelector">An asynchronous function to extract a key from an element.</param>
  33. /// <returns>An ordered async-enumerable sequence whose elements are sorted according to a key.</returns>
  34. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  35. [GenerateAsyncOverload]
  36. [Obsolete("Use OrderBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByAwait functionality now exists as an overload of OrderBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  37. private static IOrderedAsyncEnumerable<TSource> OrderByAwaitCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector) =>
  38. new OrderedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer: null, descending: false, parent: null);
  39. #if !NO_DEEP_CANCELLATION
  40. [GenerateAsyncOverload]
  41. [Obsolete("Use OrderBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByAwaitWithCancellation functionality now exists as an overload of OrderBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  42. private static IOrderedAsyncEnumerable<TSource> OrderByAwaitWithCancellationCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector) =>
  43. new OrderedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer: null, descending: false, parent: null);
  44. #endif
  45. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  46. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.orderby?view=net-9.0-pp#system-linq-asyncenumerable-orderby-2(system-collections-generic-iasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  47. /// <summary>
  48. /// Sorts the elements of a sequence in ascending order by using a specified comparer.
  49. /// </summary>
  50. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  51. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  52. /// <param name="source">An async-enumerable sequence of values to order.</param>
  53. /// <param name="keySelector">A function to extract a key from an element.</param>
  54. /// <param name="comparer">A comparer to compare keys.</param>
  55. /// <returns>An ordered async-enumerable sequence whose elements are sorted according to a key.</returns>
  56. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  57. public static IOrderedAsyncEnumerable<TSource> OrderBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) =>
  58. new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer, descending: false, parent: null);
  59. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  60. /// <summary>
  61. /// Sorts the elements of a sequence in ascending order by using a specified comparer. The keys are obtained by invoking the transform function on each element and awaiting the result.
  62. /// </summary>
  63. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  64. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  65. /// <param name="source">An async-enumerable sequence of values to order.</param>
  66. /// <param name="keySelector">An asynchronous function to extract a key from an element.</param>
  67. /// <param name="comparer">A comparer to compare keys.</param>
  68. /// <returns>An ordered async-enumerable sequence whose elements are sorted according to a key.</returns>
  69. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  70. [GenerateAsyncOverload]
  71. [Obsolete("Use OrderBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByAwait functionality now exists as an overload of OrderBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  72. private static IOrderedAsyncEnumerable<TSource> OrderByAwaitCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IComparer<TKey> comparer) =>
  73. new OrderedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer, descending: false, parent: null);
  74. #if !NO_DEEP_CANCELLATION
  75. [GenerateAsyncOverload]
  76. [Obsolete("Use OrderBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByAwaitWithCancellation functionality now exists as an overload of OrderBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  77. private static IOrderedAsyncEnumerable<TSource> OrderByAwaitWithCancellationCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IComparer<TKey> comparer) =>
  78. new OrderedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer, descending: false, parent: null);
  79. #endif
  80. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  81. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.orderbydescending?view=net-9.0-pp#system-linq-asyncenumerable-orderbydescending-2(system-collections-generic-iasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  82. // The method linked to above includes a comparer parameter with a default value of null.
  83. /// <summary>
  84. /// Sorts the elements of a sequence in descending order according to a key.
  85. /// </summary>
  86. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  87. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  88. /// <param name="source">An async-enumerable sequence of values to order.</param>
  89. /// <param name="keySelector">A function to extract a key from an element.</param>
  90. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  91. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  92. public static IOrderedAsyncEnumerable<TSource> OrderByDescending<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector) =>
  93. new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer: null, descending: true, parent: null);
  94. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  95. /// <summary>
  96. /// Sorts the elements of a sequence in descending order according to a key obtained by invoking a transform function on each element and awaiting the result.
  97. /// </summary>
  98. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  99. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  100. /// <param name="source">An async-enumerable sequence of values to order.</param>
  101. /// <param name="keySelector">An asynchronous function to extract a key from an element.</param>
  102. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  103. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  104. [GenerateAsyncOverload]
  105. [Obsolete("Use OrderByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByDescendingAwait functionality now exists as an overload of OrderByDescending. You will need to modify your callback to take an additional CancellationToken argument.")]
  106. private static IOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector) =>
  107. new OrderedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer: null, descending: true, parent: null);
  108. #if !NO_DEEP_CANCELLATION
  109. [GenerateAsyncOverload]
  110. [Obsolete("Use OrderByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByDescendingAwaitWithCancellation functionality now exists as an overload of OrderByDescending.")]
  111. private static IOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitWithCancellationCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector) =>
  112. new OrderedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer: null, descending: true, parent: null);
  113. #endif
  114. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  115. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.orderbydescending?view=net-9.0-pp#system-linq-asyncenumerable-orderbydescending-2(system-collections-generic-iasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  116. /// <summary>
  117. /// Sorts the elements of a sequence in descending order by using a specified comparer.
  118. /// </summary>
  119. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  120. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  121. /// <param name="source">An async-enumerable sequence of values to order.</param>
  122. /// <param name="keySelector">A function to extract a key from an element.</param>
  123. /// <param name="comparer">A comparer to compare keys.</param>
  124. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  125. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  126. public static IOrderedAsyncEnumerable<TSource> OrderByDescending<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) =>
  127. new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer, descending: true, parent: null);
  128. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  129. /// <summary>
  130. /// Sorts the elements of a sequence in descending order by using a specified comparer. The keys are obtained by invoking the transform function on each element and awaiting the result.
  131. /// </summary>
  132. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  133. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  134. /// <param name="source">An async-enumerable sequence of values to order.</param>
  135. /// <param name="keySelector">An asynchronous function to extract a key from an element.</param>
  136. /// <param name="comparer">A comparer to compare keys.</param>
  137. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  138. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  139. [GenerateAsyncOverload]
  140. [Obsolete("Use OrderByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByDescendingAwait functionality now exists as an overload of OrderByDescending. You will need to modify your callback to take an additional CancellationToken argument.")]
  141. private static IOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IComparer<TKey> comparer) =>
  142. new OrderedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer, descending: true, parent: null);
  143. #if !NO_DEEP_CANCELLATION
  144. [GenerateAsyncOverload]
  145. [Obsolete("Use OrderByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the OrderByDescendingAwaitWithCancellation functionality now exists as an overload of OrderByDescending.")]
  146. private static IOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitWithCancellationCore<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IComparer<TKey> comparer) =>
  147. new OrderedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer, descending: true, parent: null);
  148. #endif
  149. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  150. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.thenby?view=net-9.0-pp#system-linq-asyncenumerable-thenby-2(system-linq-iorderedasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  151. // The method linked to above includes a comparer parameter with a default value of null.
  152. /// <summary>
  153. /// Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.
  154. /// </summary>
  155. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  156. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  157. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  158. /// <param name="keySelector">A function to extract a key from each element.</param>
  159. /// <returns>An ordered async-enumerable whose elements are sorted according to a key.</returns>
  160. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  161. public static IOrderedAsyncEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  162. {
  163. if (source == null)
  164. throw Error.ArgumentNull(nameof(source));
  165. return source.CreateOrderedEnumerable(keySelector, comparer: null, descending: false);
  166. }
  167. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  168. /// <summary>
  169. /// Performs a subsequent ordering of the elements in a sequence in ascending order according to a key obtained by invoking a transform function on each element and awaiting the result.
  170. /// </summary>
  171. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  172. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  173. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  174. /// <param name="keySelector">An asynchronous function to extract a key from each element.</param>
  175. /// <returns>An ordered async-enumerable whose elements are sorted according to a key.</returns>
  176. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  177. [GenerateAsyncOverload]
  178. [Obsolete("Use ThenBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByAwait functionality now exists as an overload of ThenBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  179. private static IOrderedAsyncEnumerable<TSource> ThenByAwaitCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector)
  180. {
  181. if (source == null)
  182. throw Error.ArgumentNull(nameof(source));
  183. return source.CreateOrderedEnumerable(keySelector, comparer: default(IComparer<TKey>), descending: false);
  184. }
  185. #if !NO_DEEP_CANCELLATION
  186. [GenerateAsyncOverload]
  187. [Obsolete("Use ThenBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByAwaitWithCancellation functionality now exists as an overload of ThenBy.")]
  188. private static IOrderedAsyncEnumerable<TSource> ThenByAwaitWithCancellationCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector)
  189. {
  190. if (source == null)
  191. throw Error.ArgumentNull(nameof(source));
  192. return source.CreateOrderedEnumerable(keySelector, comparer: null, descending: false);
  193. }
  194. #endif
  195. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  196. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.thenby?view=net-9.0-pp#system-linq-asyncenumerable-thenby-2(system-linq-iorderedasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  197. /// <summary>
  198. /// Performs a subsequent ordering of the elements in a sequence in ascending order by using a specified comparer.
  199. /// </summary>
  200. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  201. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  202. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  203. /// <param name="keySelector">A function to extract a key from each element.</param>
  204. /// <param name="comparer">A comparer to compare keys.</param>
  205. /// <returns>An ordered async-enumerable whose elements are sorted according to a key.</returns>
  206. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  207. public static IOrderedAsyncEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
  208. {
  209. if (source == null)
  210. throw Error.ArgumentNull(nameof(source));
  211. return source.CreateOrderedEnumerable(keySelector, comparer, descending: false);
  212. }
  213. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  214. /// <summary>
  215. /// Performs a subsequent ordering of the elements in a sequence in ascending order by using a specified comparer. The keys are obtained by invoking a transform function on each element and awaiting the result.
  216. /// </summary>
  217. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  218. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  219. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  220. /// <param name="keySelector">An asynchronous function to extract a key from each element.</param>
  221. /// <param name="comparer">A comparer to compare keys.</param>
  222. /// <returns>An ordered async-enumerable whose elements are sorted according to a key.</returns>
  223. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  224. [GenerateAsyncOverload]
  225. [Obsolete("Use ThenBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByAwait functionality now exists as an overload of ThenBy. You will need to modify your callback to take an additional CancellationToken argument.")]
  226. private static IOrderedAsyncEnumerable<TSource> ThenByAwaitCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IComparer<TKey> comparer)
  227. {
  228. if (source == null)
  229. throw Error.ArgumentNull(nameof(source));
  230. return source.CreateOrderedEnumerable(keySelector, comparer, descending: false);
  231. }
  232. #if !NO_DEEP_CANCELLATION
  233. [GenerateAsyncOverload]
  234. [Obsolete("Use ThenBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByAwaitWithCancellation functionality now exists as an overload of ThenBy.")]
  235. private static IOrderedAsyncEnumerable<TSource> ThenByAwaitWithCancellationCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IComparer<TKey> comparer)
  236. {
  237. if (source == null)
  238. throw Error.ArgumentNull(nameof(source));
  239. return source.CreateOrderedEnumerable(keySelector, comparer, descending: false);
  240. }
  241. #endif
  242. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  243. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.thenbydescending?view=net-9.0-pp#system-linq-asyncenumerable-thenbydescending-2(system-linq-iorderedasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  244. // The method linked to above includes a comparer parameter with a default value of null.
  245. /// <summary>
  246. /// Performs a subsequent ordering of the elements in a sequence in descending order, according to a key.
  247. /// </summary>
  248. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  249. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  250. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  251. /// <param name="keySelector">A function to extract a key from each element.</param>
  252. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  253. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  254. public static IOrderedAsyncEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  255. {
  256. if (source == null)
  257. throw Error.ArgumentNull(nameof(source));
  258. return source.CreateOrderedEnumerable(keySelector, comparer: null, descending: true);
  259. }
  260. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  261. /// <summary>
  262. /// Performs a subsequent ordering of the elements in a sequence in descending order, according to a key obtained by invoking a transform function on each element and awaiting the result.
  263. /// </summary>
  264. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  265. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  266. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  267. /// <param name="keySelector">An asynchronous function to extract a key from each element.</param>
  268. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  269. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  270. [GenerateAsyncOverload]
  271. [Obsolete("Use ThenByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByDescendingAwait functionality now exists as an overload of ThenByDescending. You will need to modify your callback to take an additional CancellationToken argument.")]
  272. private static IOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector)
  273. {
  274. if (source == null)
  275. throw Error.ArgumentNull(nameof(source));
  276. return source.CreateOrderedEnumerable(keySelector, comparer: default(IComparer<TKey>), descending: true);
  277. }
  278. #if !NO_DEEP_CANCELLATION
  279. [GenerateAsyncOverload]
  280. [Obsolete("Use ThenByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByDescendingAwaitWithCancellation functionality now exists as an overload of ThenByDescending.")]
  281. private static IOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitWithCancellationCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector)
  282. {
  283. if (source == null)
  284. throw Error.ArgumentNull(nameof(source));
  285. return source.CreateOrderedEnumerable(keySelector, comparer: null, descending: true);
  286. }
  287. #endif
  288. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  289. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.thenbydescending?view=net-9.0-pp#system-linq-asyncenumerable-thenbydescending-2(system-linq-iorderedasyncenumerable((-0))-system-func((-0-1))-system-collections-generic-icomparer((-1)))
  290. /// <summary>
  291. /// Performs a subsequent ordering of the elements in a sequence in descending order by using a specified comparer.
  292. /// </summary>
  293. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  294. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  295. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  296. /// <param name="keySelector">A function to extract a key from each element.</param>
  297. /// <param name="comparer">A comparer to compare keys.</param>
  298. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  299. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  300. public static IOrderedAsyncEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
  301. {
  302. if (source == null)
  303. throw Error.ArgumentNull(nameof(source));
  304. return source.CreateOrderedEnumerable(keySelector, comparer, descending: true);
  305. }
  306. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  307. /// <summary>
  308. /// Performs a subsequent ordering of the elements in a sequence in descending order by using a specified comparer. The keys are obtained by invoking a transform function on each element and awaiting the result.
  309. /// </summary>
  310. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  311. /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
  312. /// <param name="source">An ordered async-enumerable sequence that contains elements to sort.</param>
  313. /// <param name="keySelector">An asynchronous function to extract a key from each element.</param>
  314. /// <param name="comparer">A comparer to compare keys.</param>
  315. /// <returns>An ordered async-enumerable sequence whose elements are sorted in descending order according to a key.</returns>
  316. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  317. [GenerateAsyncOverload]
  318. [Obsolete("Use ThenByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByDescendingAwait functionality now exists as an overload of ThenByDescending. You will need to modify your callback to take an additional CancellationToken argument.")]
  319. private static IOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IComparer<TKey> comparer)
  320. {
  321. if (source == null)
  322. throw Error.ArgumentNull(nameof(source));
  323. return source.CreateOrderedEnumerable(keySelector, comparer, descending: true);
  324. }
  325. #if !NO_DEEP_CANCELLATION
  326. [GenerateAsyncOverload]
  327. [Obsolete("Use ThenByDescending. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ThenByDescendingAwaitWithCancellation functionality now exists as an overload of ThenByDescending.")]
  328. private static IOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitWithCancellationCore<TSource, TKey>(this IOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IComparer<TKey> comparer)
  329. {
  330. if (source == null)
  331. throw Error.ArgumentNull(nameof(source));
  332. return source.CreateOrderedEnumerable(keySelector, comparer, descending: true);
  333. }
  334. #endif
  335. }
  336. }