Distinct.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerableEx
  10. {
  11. /// <summary>
  12. /// Returns an async-enumerable sequence that contains only distinct elements according to the keySelector.
  13. /// </summary>
  14. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  15. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  16. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  17. /// <param name="keySelector">A function to compute the comparison key for each element.</param>
  18. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  19. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  20. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  21. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  22. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  23. {
  24. if (source == null)
  25. throw Error.ArgumentNull(nameof(source));
  26. if (keySelector == null)
  27. throw Error.ArgumentNull(nameof(keySelector));
  28. return DistinctCore(source, keySelector, comparer: null);
  29. }
  30. /// <summary>
  31. /// Returns an async-enumerable sequence that contains only distinct elements according to the keySelector and the comparer.
  32. /// </summary>
  33. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  34. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  35. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  36. /// <param name="keySelector">A function to compute the comparison key for each element.</param>
  37. /// <param name="comparer">Equality comparer for source elements.</param>
  38. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  39. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
  40. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  41. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  42. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
  43. {
  44. if (source == null)
  45. throw Error.ArgumentNull(nameof(source));
  46. if (keySelector == null)
  47. throw Error.ArgumentNull(nameof(keySelector));
  48. return DistinctCore(source, keySelector, comparer);
  49. }
  50. /// <summary>
  51. /// Returns an async-enumerable sequence that contains only distinct elements according to the asynchronous keySelector.
  52. /// </summary>
  53. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  54. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  55. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  56. /// <param name="keySelector">An asynchronous function to compute the comparison key for each element.</param>
  57. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  58. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  59. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  60. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  61. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector)
  62. {
  63. if (source == null)
  64. throw Error.ArgumentNull(nameof(source));
  65. if (keySelector == null)
  66. throw Error.ArgumentNull(nameof(keySelector));
  67. return DistinctCore<TSource, TKey>(source, keySelector, comparer: null);
  68. }
  69. #if !NO_DEEP_CANCELLATION
  70. /// <summary>
  71. /// Returns an async-enumerable sequence that contains only distinct elements according to the asynchronous (cancellable) keySelector.
  72. /// </summary>
  73. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  74. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  75. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  76. /// <param name="keySelector">An asynchronous (cancellable) function to compute the comparison key for each element.</param>
  77. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  78. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
  79. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  80. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  81. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector)
  82. {
  83. if (source == null)
  84. throw Error.ArgumentNull(nameof(source));
  85. if (keySelector == null)
  86. throw Error.ArgumentNull(nameof(keySelector));
  87. return DistinctCore<TSource, TKey>(source, keySelector, comparer: null);
  88. }
  89. #endif
  90. /// <summary>
  91. /// Returns an async-enumerable sequence that contains only distinct elements according to the asynchronous keySelector and the comparer.
  92. /// </summary>
  93. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  94. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  95. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  96. /// <param name="keySelector">An asynchronous function to compute the comparison key for each element.</param>
  97. /// <param name="comparer">Equality comparer for source elements.</param>
  98. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  99. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
  100. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  101. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  102. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  103. {
  104. if (source == null)
  105. throw Error.ArgumentNull(nameof(source));
  106. if (keySelector == null)
  107. throw Error.ArgumentNull(nameof(keySelector));
  108. return DistinctCore(source, keySelector, comparer);
  109. }
  110. #if !NO_DEEP_CANCELLATION
  111. /// <summary>
  112. /// Returns an async-enumerable sequence that contains only distinct elements according to the asynchronous (cancellable) keySelector and the comparer.
  113. /// </summary>
  114. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  115. /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
  116. /// <param name="source">An async-enumerable sequence to retain distinct elements for.</param>
  117. /// <param name="keySelector">An asynchronous (cancellable) function to compute the comparison key for each element.</param>
  118. /// <param name="comparer">Equality comparer for source elements.</param>
  119. /// <returns>An async-enumerable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
  120. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
  121. /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
  122. [Obsolete("Use DistinctBy. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the functionality of selector-based overloads of Distinct now exists as DistinctBy.")]
  123. public static IAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  124. {
  125. if (source == null)
  126. throw Error.ArgumentNull(nameof(source));
  127. if (keySelector == null)
  128. throw Error.ArgumentNull(nameof(keySelector));
  129. return DistinctCore(source, keySelector, comparer);
  130. }
  131. #endif
  132. private static IAsyncEnumerable<TSource> DistinctCore<TSource, TKey>(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
  133. {
  134. return new DistinctAsyncIterator<TSource, TKey>(source, keySelector, comparer);
  135. }
  136. private static IAsyncEnumerable<TSource> DistinctCore<TSource, TKey>(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  137. {
  138. return new DistinctAsyncIteratorWithTask<TSource, TKey>(source, keySelector, comparer);
  139. }
  140. #if !NO_DEEP_CANCELLATION
  141. private static IAsyncEnumerable<TSource> DistinctCore<TSource, TKey>(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  142. {
  143. return new DistinctAsyncIteratorWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer);
  144. }
  145. #endif
  146. private sealed class DistinctAsyncIterator<TSource, TKey> : AsyncIterator<TSource>, IAsyncIListProvider<TSource>
  147. {
  148. private readonly IEqualityComparer<TKey>? _comparer;
  149. private readonly Func<TSource, TKey> _keySelector;
  150. private readonly IAsyncEnumerable<TSource> _source;
  151. private IAsyncEnumerator<TSource>? _enumerator;
  152. private Set<TKey>? _set;
  153. public DistinctAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
  154. {
  155. _source = source;
  156. _keySelector = keySelector;
  157. _comparer = comparer;
  158. }
  159. public async ValueTask<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
  160. {
  161. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  162. return s.ToArray();
  163. }
  164. public async ValueTask<List<TSource>> ToListAsync(CancellationToken cancellationToken)
  165. {
  166. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  167. return s;
  168. }
  169. public async ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  170. {
  171. if (onlyIfCheap)
  172. {
  173. return -1;
  174. }
  175. var count = 0;
  176. var s = new Set<TKey>(_comparer);
  177. var enu = _source.GetAsyncEnumerator(cancellationToken);
  178. try
  179. {
  180. while (await enu.MoveNextAsync().ConfigureAwait(false))
  181. {
  182. var item = enu.Current;
  183. if (s.Add(_keySelector(item)))
  184. {
  185. count++;
  186. }
  187. }
  188. }
  189. finally
  190. {
  191. await enu.DisposeAsync().ConfigureAwait(false);
  192. }
  193. return count;
  194. }
  195. public override AsyncIteratorBase<TSource> Clone()
  196. {
  197. return new DistinctAsyncIterator<TSource, TKey>(_source, _keySelector, _comparer);
  198. }
  199. public override async ValueTask DisposeAsync()
  200. {
  201. if (_enumerator != null)
  202. {
  203. await _enumerator.DisposeAsync().ConfigureAwait(false);
  204. _enumerator = null;
  205. _set = null;
  206. }
  207. await base.DisposeAsync().ConfigureAwait(false);
  208. }
  209. protected override async ValueTask<bool> MoveNextCore()
  210. {
  211. switch (_state)
  212. {
  213. case AsyncIteratorState.Allocated:
  214. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  215. if (!await _enumerator.MoveNextAsync().ConfigureAwait(false))
  216. {
  217. await DisposeAsync().ConfigureAwait(false);
  218. return false;
  219. }
  220. var element = _enumerator.Current;
  221. _set = new Set<TKey>(_comparer);
  222. _set.Add(_keySelector(element));
  223. _current = element;
  224. _state = AsyncIteratorState.Iterating;
  225. return true;
  226. case AsyncIteratorState.Iterating:
  227. while (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  228. {
  229. element = _enumerator.Current;
  230. if (_set!.Add(_keySelector(element)))
  231. {
  232. _current = element;
  233. return true;
  234. }
  235. }
  236. break;
  237. }
  238. await DisposeAsync().ConfigureAwait(false);
  239. return false;
  240. }
  241. private async Task<List<TSource>> FillSetAsync(CancellationToken cancellationToken)
  242. {
  243. var s = new Set<TKey>(_comparer);
  244. var r = new List<TSource>();
  245. var enu = _source.GetAsyncEnumerator(cancellationToken);
  246. try
  247. {
  248. while (await enu.MoveNextAsync().ConfigureAwait(false))
  249. {
  250. var item = enu.Current;
  251. if (s.Add(_keySelector(item)))
  252. {
  253. r.Add(item);
  254. }
  255. }
  256. }
  257. finally
  258. {
  259. await enu.DisposeAsync().ConfigureAwait(false);
  260. }
  261. return r;
  262. }
  263. }
  264. private sealed class DistinctAsyncIteratorWithTask<TSource, TKey> : AsyncIterator<TSource>, IAsyncIListProvider<TSource>
  265. {
  266. private readonly IEqualityComparer<TKey>? _comparer;
  267. private readonly Func<TSource, ValueTask<TKey>> _keySelector;
  268. private readonly IAsyncEnumerable<TSource> _source;
  269. private IAsyncEnumerator<TSource>? _enumerator;
  270. private Set<TKey>? _set;
  271. public DistinctAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  272. {
  273. _source = source;
  274. _keySelector = keySelector;
  275. _comparer = comparer;
  276. }
  277. public async ValueTask<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
  278. {
  279. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  280. return s.ToArray();
  281. }
  282. public async ValueTask<List<TSource>> ToListAsync(CancellationToken cancellationToken)
  283. {
  284. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  285. return s;
  286. }
  287. public async ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  288. {
  289. if (onlyIfCheap)
  290. {
  291. return -1;
  292. }
  293. var count = 0;
  294. var s = new Set<TKey>(_comparer);
  295. var enu = _source.GetAsyncEnumerator(cancellationToken);
  296. try
  297. {
  298. while (await enu.MoveNextAsync().ConfigureAwait(false))
  299. {
  300. var item = enu.Current;
  301. if (s.Add(await _keySelector(item).ConfigureAwait(false)))
  302. {
  303. count++;
  304. }
  305. }
  306. }
  307. finally
  308. {
  309. await enu.DisposeAsync().ConfigureAwait(false);
  310. }
  311. return count;
  312. }
  313. public override AsyncIteratorBase<TSource> Clone()
  314. {
  315. return new DistinctAsyncIteratorWithTask<TSource, TKey>(_source, _keySelector, _comparer);
  316. }
  317. public override async ValueTask DisposeAsync()
  318. {
  319. if (_enumerator != null)
  320. {
  321. await _enumerator.DisposeAsync().ConfigureAwait(false);
  322. _enumerator = null;
  323. _set = null;
  324. }
  325. await base.DisposeAsync().ConfigureAwait(false);
  326. }
  327. protected override async ValueTask<bool> MoveNextCore()
  328. {
  329. switch (_state)
  330. {
  331. case AsyncIteratorState.Allocated:
  332. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  333. if (!await _enumerator.MoveNextAsync().ConfigureAwait(false))
  334. {
  335. await DisposeAsync().ConfigureAwait(false);
  336. return false;
  337. }
  338. var element = _enumerator.Current;
  339. _set = new Set<TKey>(_comparer);
  340. _set.Add(await _keySelector(element).ConfigureAwait(false));
  341. _current = element;
  342. _state = AsyncIteratorState.Iterating;
  343. return true;
  344. case AsyncIteratorState.Iterating:
  345. while (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  346. {
  347. element = _enumerator.Current;
  348. if (_set!.Add(await _keySelector(element).ConfigureAwait(false)))
  349. {
  350. _current = element;
  351. return true;
  352. }
  353. }
  354. break;
  355. }
  356. await DisposeAsync().ConfigureAwait(false);
  357. return false;
  358. }
  359. private async ValueTask<List<TSource>> FillSetAsync(CancellationToken cancellationToken)
  360. {
  361. var s = new Set<TKey>(_comparer);
  362. var r = new List<TSource>();
  363. var enu = _source.GetAsyncEnumerator(cancellationToken);
  364. try
  365. {
  366. while (await enu.MoveNextAsync().ConfigureAwait(false))
  367. {
  368. var item = enu.Current;
  369. if (s.Add(await _keySelector(item).ConfigureAwait(false)))
  370. {
  371. r.Add(item);
  372. }
  373. }
  374. }
  375. finally
  376. {
  377. await enu.DisposeAsync().ConfigureAwait(false);
  378. }
  379. return r;
  380. }
  381. }
  382. #if !NO_DEEP_CANCELLATION
  383. private sealed class DistinctAsyncIteratorWithTaskAndCancellation<TSource, TKey> : AsyncIterator<TSource>, IAsyncIListProvider<TSource>
  384. {
  385. private readonly IEqualityComparer<TKey>? _comparer;
  386. private readonly Func<TSource, CancellationToken, ValueTask<TKey>> _keySelector;
  387. private readonly IAsyncEnumerable<TSource> _source;
  388. private IAsyncEnumerator<TSource>? _enumerator;
  389. private Set<TKey>? _set;
  390. public DistinctAsyncIteratorWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey>? comparer)
  391. {
  392. _source = source;
  393. _keySelector = keySelector;
  394. _comparer = comparer;
  395. }
  396. public async ValueTask<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
  397. {
  398. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  399. return s.ToArray();
  400. }
  401. public async ValueTask<List<TSource>> ToListAsync(CancellationToken cancellationToken)
  402. {
  403. var s = await FillSetAsync(cancellationToken).ConfigureAwait(false);
  404. return s;
  405. }
  406. public async ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  407. {
  408. if (onlyIfCheap)
  409. {
  410. return -1;
  411. }
  412. var count = 0;
  413. var s = new Set<TKey>(_comparer);
  414. var enu = _source.GetAsyncEnumerator(cancellationToken);
  415. try
  416. {
  417. while (await enu.MoveNextAsync().ConfigureAwait(false))
  418. {
  419. var item = enu.Current;
  420. if (s.Add(await _keySelector(item, cancellationToken).ConfigureAwait(false)))
  421. {
  422. count++;
  423. }
  424. }
  425. }
  426. finally
  427. {
  428. await enu.DisposeAsync().ConfigureAwait(false);
  429. }
  430. return count;
  431. }
  432. public override AsyncIteratorBase<TSource> Clone()
  433. {
  434. return new DistinctAsyncIteratorWithTaskAndCancellation<TSource, TKey>(_source, _keySelector, _comparer);
  435. }
  436. public override async ValueTask DisposeAsync()
  437. {
  438. if (_enumerator != null)
  439. {
  440. await _enumerator.DisposeAsync().ConfigureAwait(false);
  441. _enumerator = null;
  442. _set = null;
  443. }
  444. await base.DisposeAsync().ConfigureAwait(false);
  445. }
  446. protected override async ValueTask<bool> MoveNextCore()
  447. {
  448. switch (_state)
  449. {
  450. case AsyncIteratorState.Allocated:
  451. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  452. if (!await _enumerator.MoveNextAsync().ConfigureAwait(false))
  453. {
  454. await DisposeAsync().ConfigureAwait(false);
  455. return false;
  456. }
  457. var element = _enumerator.Current;
  458. _set = new Set<TKey>(_comparer);
  459. _set.Add(await _keySelector(element, _cancellationToken).ConfigureAwait(false));
  460. _current = element;
  461. _state = AsyncIteratorState.Iterating;
  462. return true;
  463. case AsyncIteratorState.Iterating:
  464. while (await _enumerator!.MoveNextAsync().ConfigureAwait(false))
  465. {
  466. element = _enumerator.Current;
  467. if (_set!.Add(await _keySelector(element, _cancellationToken).ConfigureAwait(false)))
  468. {
  469. _current = element;
  470. return true;
  471. }
  472. }
  473. break;
  474. }
  475. await DisposeAsync().ConfigureAwait(false);
  476. return false;
  477. }
  478. private async ValueTask<List<TSource>> FillSetAsync(CancellationToken cancellationToken)
  479. {
  480. var s = new Set<TKey>(_comparer);
  481. var r = new List<TSource>();
  482. var enu = _source.GetAsyncEnumerator(cancellationToken);
  483. try
  484. {
  485. while (await enu.MoveNextAsync().ConfigureAwait(false))
  486. {
  487. var item = enu.Current;
  488. if (s.Add(await _keySelector(item, cancellationToken).ConfigureAwait(false)))
  489. {
  490. r.Add(item);
  491. }
  492. }
  493. }
  494. finally
  495. {
  496. await enu.DisposeAsync().ConfigureAwait(false);
  497. }
  498. return r;
  499. }
  500. }
  501. #endif
  502. }
  503. }