Select.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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. /// <summary>
  12. /// Projects each element of an async-enumerable sequence into a new form.
  13. /// </summary>
  14. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  15. /// <typeparam name="TResult">The type of the elements in the result sequence, obtained by running the selector function for each element in the source sequence.</typeparam>
  16. /// <param name="source">A sequence of elements to invoke a transform function on.</param>
  17. /// <param name="selector">A transform function to apply to each source element.</param>
  18. /// <returns>An async-enumerable sequence whose elements are the result of invoking the transform function on each element of source.</returns>
  19. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  20. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
  21. {
  22. if (source == null)
  23. throw Error.ArgumentNull(nameof(source));
  24. if (selector == null)
  25. throw Error.ArgumentNull(nameof(selector));
  26. return source switch
  27. {
  28. AsyncIterator<TSource> iterator => iterator.Select(selector),
  29. IList<TSource> list => new SelectIListIterator<TSource, TResult>(list, selector),
  30. _ => new SelectEnumerableAsyncIterator<TSource, TResult>(source, selector),
  31. };
  32. }
  33. /// <summary>
  34. /// Projects each element of an async-enumerable sequence into a new form by incorporating the element's index.
  35. /// </summary>
  36. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  37. /// <typeparam name="TResult">The type of the elements in the result sequence, obtained by running the selector function for each element in the source sequence.</typeparam>
  38. /// <param name="source">A sequence of elements to invoke a transform function on.</param>
  39. /// <param name="selector">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>
  40. /// <returns>An async-enumerable sequence whose elements are the result of invoking the transform function on each element of source.</returns>
  41. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  42. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector)
  43. {
  44. if (source == null)
  45. throw Error.ArgumentNull(nameof(source));
  46. if (selector == null)
  47. throw Error.ArgumentNull(nameof(selector));
  48. return Core(source, selector);
  49. static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  50. {
  51. var index = -1;
  52. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  53. {
  54. checked
  55. {
  56. index++;
  57. }
  58. yield return selector(element, index);
  59. }
  60. }
  61. }
  62. /// <summary>
  63. /// Projects each element of an async-enumerable sequence into a new form by applying an asynchronous selector function to each member of the source sequence and awaiting the result.
  64. /// </summary>
  65. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  66. /// <typeparam name="TResult">The type of the elements in the result sequence, obtained by running the selector function for each element in the source sequence and awaiting the result.</typeparam>
  67. /// <param name="source">A sequence of elements to invoke a transform function on.</param>
  68. /// <param name="selector">An asynchronous transform function to apply to each source element.</param>
  69. /// <returns>An async-enumerable sequence whose elements are the result of invoking the transform function on each element of the source sequence and awaiting the result.</returns>
  70. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  71. [GenerateAsyncOverload]
  72. private static IAsyncEnumerable<TResult> SelectAwaitCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector)
  73. {
  74. if (source == null)
  75. throw Error.ArgumentNull(nameof(source));
  76. if (selector == null)
  77. throw Error.ArgumentNull(nameof(selector));
  78. return source switch
  79. {
  80. AsyncIterator<TSource> iterator => iterator.Select(selector),
  81. IList<TSource> list => new SelectIListIteratorWithTask<TSource, TResult>(list, selector),
  82. _ => new SelectEnumerableAsyncIteratorWithTask<TSource, TResult>(source, selector),
  83. };
  84. }
  85. #if !NO_DEEP_CANCELLATION
  86. [GenerateAsyncOverload]
  87. private static IAsyncEnumerable<TResult> SelectAwaitWithCancellationCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector)
  88. {
  89. if (source == null)
  90. throw Error.ArgumentNull(nameof(source));
  91. if (selector == null)
  92. throw Error.ArgumentNull(nameof(selector));
  93. return source switch
  94. {
  95. AsyncIterator<TSource> iterator => iterator.Select(selector),
  96. IList<TSource> list => new SelectIListIteratorWithTaskAndCancellation<TSource, TResult>(list, selector),
  97. _ => new SelectEnumerableAsyncIteratorWithTaskAndCancellation<TSource, TResult>(source, selector),
  98. };
  99. }
  100. #endif
  101. /// <summary>
  102. /// Projects each element of an async-enumerable sequence into a new form by applying an asynchronous selector function that incorporates each element's index to each element of the source sequence and awaiting the result.
  103. /// </summary>
  104. /// <typeparam name="TSource">The type of elements in the source sequence.</typeparam>
  105. /// <typeparam name="TResult">The type of elements in the result sequence, obtained by running the selector function for each element and its index, and awaiting the result.</typeparam>
  106. /// <param name="source">A sequence of elements to invoke a transform function on.</param>
  107. /// <param name="selector">An asynchronous transform function to apply to each source element; the second parameter represents the index of the element.</param>
  108. /// <returns>An async-enumerable sequence whose elements are the result of invoking the transform function on each element and its index of the source sequence and awaiting the result.</returns>
  109. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  110. [GenerateAsyncOverload]
  111. private static IAsyncEnumerable<TResult> SelectAwaitCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<TResult>> selector)
  112. {
  113. if (source == null)
  114. throw Error.ArgumentNull(nameof(source));
  115. if (selector == null)
  116. throw Error.ArgumentNull(nameof(selector));
  117. return Core(source, selector);
  118. static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  119. {
  120. var index = -1;
  121. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  122. {
  123. checked
  124. {
  125. index++;
  126. }
  127. yield return await selector(element, index).ConfigureAwait(false);
  128. }
  129. }
  130. }
  131. #if !NO_DEEP_CANCELLATION
  132. [GenerateAsyncOverload]
  133. private static IAsyncEnumerable<TResult> SelectAwaitWithCancellationCore<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<TResult>> selector)
  134. {
  135. if (source == null)
  136. throw Error.ArgumentNull(nameof(source));
  137. if (selector == null)
  138. throw Error.ArgumentNull(nameof(selector));
  139. return Core(source, selector);
  140. static async IAsyncEnumerable<TResult> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<TResult>> selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  141. {
  142. var index = -1;
  143. await foreach (var element in source.WithCancellation(cancellationToken).ConfigureAwait(false))
  144. {
  145. checked
  146. {
  147. index++;
  148. }
  149. yield return await selector(element, index, cancellationToken).ConfigureAwait(false);
  150. }
  151. }
  152. }
  153. #endif
  154. internal sealed class SelectEnumerableAsyncIterator<TSource, TResult> : AsyncIterator<TResult>
  155. {
  156. private readonly Func<TSource, TResult> _selector;
  157. private readonly IAsyncEnumerable<TSource> _source;
  158. private IAsyncEnumerator<TSource>? _enumerator;
  159. public SelectEnumerableAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
  160. {
  161. _source = source;
  162. _selector = selector;
  163. }
  164. public override AsyncIteratorBase<TResult> Clone()
  165. {
  166. return new SelectEnumerableAsyncIterator<TSource, TResult>(_source, _selector);
  167. }
  168. public override async ValueTask DisposeAsync()
  169. {
  170. if (_enumerator != null)
  171. {
  172. await _enumerator.DisposeAsync().ConfigureAwait(false);
  173. _enumerator = null;
  174. }
  175. await base.DisposeAsync().ConfigureAwait(false);
  176. }
  177. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, TResult1> selector)
  178. {
  179. return new SelectEnumerableAsyncIterator<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  180. }
  181. protected override async ValueTask<bool> MoveNextCore()
  182. {
  183. switch (_state)
  184. {
  185. case AsyncIteratorState.Allocated:
  186. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  187. _state = AsyncIteratorState.Iterating;
  188. goto case AsyncIteratorState.Iterating;
  189. case AsyncIteratorState.Iterating:
  190. if (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  191. {
  192. _current = _selector(_enumerator.Current);
  193. return true;
  194. }
  195. break;
  196. }
  197. await DisposeAsync().ConfigureAwait(false);
  198. return false;
  199. }
  200. }
  201. internal sealed class SelectIListIterator<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  202. {
  203. private readonly Func<TSource, TResult> _selector;
  204. private readonly IList<TSource> _source;
  205. private IEnumerator<TSource>? _enumerator;
  206. public SelectIListIterator(IList<TSource> source, Func<TSource, TResult> selector)
  207. {
  208. _source = source;
  209. _selector = selector;
  210. }
  211. public override AsyncIteratorBase<TResult> Clone()
  212. {
  213. return new SelectIListIterator<TSource, TResult>(_source, _selector);
  214. }
  215. public override async ValueTask DisposeAsync()
  216. {
  217. if (_enumerator != null)
  218. {
  219. _enumerator.Dispose();
  220. _enumerator = null;
  221. }
  222. await base.DisposeAsync().ConfigureAwait(false);
  223. }
  224. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  225. {
  226. if (onlyIfCheap)
  227. {
  228. return new ValueTask<int>(-1);
  229. }
  230. cancellationToken.ThrowIfCancellationRequested();
  231. var count = 0;
  232. foreach (var item in _source)
  233. {
  234. _selector(item);
  235. checked
  236. {
  237. count++;
  238. }
  239. }
  240. return new ValueTask<int>(count);
  241. }
  242. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, TResult1> selector)
  243. {
  244. return new SelectIListIterator<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  245. }
  246. public ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  247. {
  248. cancellationToken.ThrowIfCancellationRequested();
  249. var n = _source.Count;
  250. var res = new TResult[n];
  251. for (var i = 0; i < n; i++)
  252. {
  253. res[i] = _selector(_source[i]);
  254. }
  255. return new ValueTask<TResult[]>(res);
  256. }
  257. public ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  258. {
  259. cancellationToken.ThrowIfCancellationRequested();
  260. var n = _source.Count;
  261. var res = new List<TResult>(n);
  262. for (var i = 0; i < n; i++)
  263. {
  264. res.Add(_selector(_source[i]));
  265. }
  266. return new ValueTask<List<TResult>>(res);
  267. }
  268. protected override async ValueTask<bool> MoveNextCore()
  269. {
  270. switch (_state)
  271. {
  272. case AsyncIteratorState.Allocated:
  273. _enumerator = _source.GetEnumerator();
  274. _state = AsyncIteratorState.Iterating;
  275. goto case AsyncIteratorState.Iterating;
  276. case AsyncIteratorState.Iterating:
  277. if (_enumerator!.MoveNext())
  278. {
  279. _current = _selector(_enumerator.Current);
  280. return true;
  281. }
  282. await DisposeAsync().ConfigureAwait(false);
  283. break;
  284. }
  285. return false;
  286. }
  287. }
  288. internal sealed class SelectEnumerableAsyncIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>
  289. {
  290. private readonly Func<TSource, ValueTask<TResult>> _selector;
  291. private readonly IAsyncEnumerable<TSource> _source;
  292. private IAsyncEnumerator<TSource>? _enumerator;
  293. public SelectEnumerableAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> selector)
  294. {
  295. _source = source;
  296. _selector = selector;
  297. }
  298. public override AsyncIteratorBase<TResult> Clone()
  299. {
  300. return new SelectEnumerableAsyncIteratorWithTask<TSource, TResult>(_source, _selector);
  301. }
  302. public override async ValueTask DisposeAsync()
  303. {
  304. if (_enumerator != null)
  305. {
  306. await _enumerator.DisposeAsync().ConfigureAwait(false);
  307. _enumerator = null;
  308. }
  309. await base.DisposeAsync().ConfigureAwait(false);
  310. }
  311. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, ValueTask<TResult1>> selector)
  312. {
  313. return new SelectEnumerableAsyncIteratorWithTask<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  314. }
  315. protected override async ValueTask<bool> MoveNextCore()
  316. {
  317. switch (_state)
  318. {
  319. case AsyncIteratorState.Allocated:
  320. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  321. _state = AsyncIteratorState.Iterating;
  322. goto case AsyncIteratorState.Iterating;
  323. case AsyncIteratorState.Iterating:
  324. if (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  325. {
  326. _current = await _selector(_enumerator.Current).ConfigureAwait(false);
  327. return true;
  328. }
  329. break;
  330. }
  331. await DisposeAsync().ConfigureAwait(false);
  332. return false;
  333. }
  334. }
  335. #if !NO_DEEP_CANCELLATION
  336. internal sealed class SelectEnumerableAsyncIteratorWithTaskAndCancellation<TSource, TResult> : AsyncIterator<TResult>
  337. {
  338. private readonly Func<TSource, CancellationToken, ValueTask<TResult>> _selector;
  339. private readonly IAsyncEnumerable<TSource> _source;
  340. private IAsyncEnumerator<TSource>? _enumerator;
  341. public SelectEnumerableAsyncIteratorWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector)
  342. {
  343. _source = source;
  344. _selector = selector;
  345. }
  346. public override AsyncIteratorBase<TResult> Clone()
  347. {
  348. return new SelectEnumerableAsyncIteratorWithTaskAndCancellation<TSource, TResult>(_source, _selector);
  349. }
  350. public override async ValueTask DisposeAsync()
  351. {
  352. if (_enumerator != null)
  353. {
  354. await _enumerator.DisposeAsync().ConfigureAwait(false);
  355. _enumerator = null;
  356. }
  357. await base.DisposeAsync().ConfigureAwait(false);
  358. }
  359. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, CancellationToken, ValueTask<TResult1>> selector)
  360. {
  361. return new SelectEnumerableAsyncIteratorWithTaskAndCancellation<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  362. }
  363. protected override async ValueTask<bool> MoveNextCore()
  364. {
  365. switch (_state)
  366. {
  367. case AsyncIteratorState.Allocated:
  368. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  369. _state = AsyncIteratorState.Iterating;
  370. goto case AsyncIteratorState.Iterating;
  371. case AsyncIteratorState.Iterating:
  372. if (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  373. {
  374. _current = await _selector(_enumerator.Current, _cancellationToken).ConfigureAwait(false);
  375. return true;
  376. }
  377. break;
  378. }
  379. await DisposeAsync().ConfigureAwait(false);
  380. return false;
  381. }
  382. }
  383. #endif
  384. // NB: LINQ to Objects implements IPartition<TResult> for this. However, it seems incorrect to do so in a trivial
  385. // manner where e.g. TryGetLast simply indexes into the list without running the selector for the first n - 1
  386. // elements in order to ensure side-effects. We should consider whether we want to follow this implementation
  387. // strategy or support IAsyncPartition<TResult> in a less efficient but more correct manner here.
  388. private sealed class SelectIListIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  389. {
  390. private readonly Func<TSource, ValueTask<TResult>> _selector;
  391. private readonly IList<TSource> _source;
  392. private IEnumerator<TSource>? _enumerator;
  393. public SelectIListIteratorWithTask(IList<TSource> source, Func<TSource, ValueTask<TResult>> selector)
  394. {
  395. _source = source;
  396. _selector = selector;
  397. }
  398. public override AsyncIteratorBase<TResult> Clone()
  399. {
  400. return new SelectIListIteratorWithTask<TSource, TResult>(_source, _selector);
  401. }
  402. public override async ValueTask DisposeAsync()
  403. {
  404. if (_enumerator != null)
  405. {
  406. _enumerator.Dispose();
  407. _enumerator = null;
  408. }
  409. await base.DisposeAsync().ConfigureAwait(false);
  410. }
  411. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  412. {
  413. if (onlyIfCheap)
  414. {
  415. return new ValueTask<int>(-1);
  416. }
  417. return Core();
  418. async ValueTask<int> Core()
  419. {
  420. cancellationToken.ThrowIfCancellationRequested();
  421. var count = 0;
  422. foreach (var item in _source)
  423. {
  424. await _selector(item).ConfigureAwait(false);
  425. checked
  426. {
  427. count++;
  428. }
  429. }
  430. return count;
  431. }
  432. }
  433. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, ValueTask<TResult1>> selector)
  434. {
  435. return new SelectIListIteratorWithTask<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  436. }
  437. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  438. {
  439. cancellationToken.ThrowIfCancellationRequested();
  440. var n = _source.Count;
  441. var res = new TResult[n];
  442. for (var i = 0; i < n; i++)
  443. {
  444. res[i] = await _selector(_source[i]).ConfigureAwait(false);
  445. }
  446. return res;
  447. }
  448. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  449. {
  450. cancellationToken.ThrowIfCancellationRequested();
  451. var n = _source.Count;
  452. var res = new List<TResult>(n);
  453. for (var i = 0; i < n; i++)
  454. {
  455. res.Add(await _selector(_source[i]).ConfigureAwait(false));
  456. }
  457. return res;
  458. }
  459. protected override async ValueTask<bool> MoveNextCore()
  460. {
  461. switch (_state)
  462. {
  463. case AsyncIteratorState.Allocated:
  464. _enumerator = _source.GetEnumerator();
  465. _state = AsyncIteratorState.Iterating;
  466. goto case AsyncIteratorState.Iterating;
  467. case AsyncIteratorState.Iterating:
  468. if (_enumerator!.MoveNext())
  469. {
  470. _current = await _selector(_enumerator.Current).ConfigureAwait(false);
  471. return true;
  472. }
  473. break;
  474. }
  475. await DisposeAsync().ConfigureAwait(false);
  476. return false;
  477. }
  478. }
  479. #if !NO_DEEP_CANCELLATION
  480. private sealed class SelectIListIteratorWithTaskAndCancellation<TSource, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  481. {
  482. private readonly Func<TSource, CancellationToken, ValueTask<TResult>> _selector;
  483. private readonly IList<TSource> _source;
  484. private IEnumerator<TSource>? _enumerator;
  485. public SelectIListIteratorWithTaskAndCancellation(IList<TSource> source, Func<TSource, CancellationToken, ValueTask<TResult>> selector)
  486. {
  487. _source = source;
  488. _selector = selector;
  489. }
  490. public override AsyncIteratorBase<TResult> Clone()
  491. {
  492. return new SelectIListIteratorWithTaskAndCancellation<TSource, TResult>(_source, _selector);
  493. }
  494. public override async ValueTask DisposeAsync()
  495. {
  496. if (_enumerator != null)
  497. {
  498. _enumerator.Dispose();
  499. _enumerator = null;
  500. }
  501. await base.DisposeAsync().ConfigureAwait(false);
  502. }
  503. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  504. {
  505. if (onlyIfCheap)
  506. {
  507. return new ValueTask<int>(-1);
  508. }
  509. return Core();
  510. async ValueTask<int> Core()
  511. {
  512. cancellationToken.ThrowIfCancellationRequested();
  513. var count = 0;
  514. foreach (var item in _source)
  515. {
  516. await _selector(item, cancellationToken).ConfigureAwait(false);
  517. checked
  518. {
  519. count++;
  520. }
  521. }
  522. return count;
  523. }
  524. }
  525. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, CancellationToken, ValueTask<TResult1>> selector)
  526. {
  527. return new SelectIListIteratorWithTaskAndCancellation<TSource, TResult1>(_source, CombineSelectors(_selector, selector));
  528. }
  529. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  530. {
  531. cancellationToken.ThrowIfCancellationRequested();
  532. var n = _source.Count;
  533. var res = new TResult[n];
  534. for (var i = 0; i < n; i++)
  535. {
  536. res[i] = await _selector(_source[i], cancellationToken).ConfigureAwait(false);
  537. }
  538. return res;
  539. }
  540. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  541. {
  542. cancellationToken.ThrowIfCancellationRequested();
  543. var n = _source.Count;
  544. var res = new List<TResult>(n);
  545. for (var i = 0; i < n; i++)
  546. {
  547. res.Add(await _selector(_source[i], cancellationToken).ConfigureAwait(false));
  548. }
  549. return res;
  550. }
  551. protected override async ValueTask<bool> MoveNextCore()
  552. {
  553. switch (_state)
  554. {
  555. case AsyncIteratorState.Allocated:
  556. _enumerator = _source.GetEnumerator();
  557. _state = AsyncIteratorState.Iterating;
  558. goto case AsyncIteratorState.Iterating;
  559. case AsyncIteratorState.Iterating:
  560. if (_enumerator!.MoveNext())
  561. {
  562. _current = await _selector(_enumerator.Current, _cancellationToken).ConfigureAwait(false);
  563. return true;
  564. }
  565. break;
  566. }
  567. await DisposeAsync().ConfigureAwait(false);
  568. return false;
  569. }
  570. }
  571. #endif
  572. }
  573. }