OrderBy.cs 30 KB

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