OrderedAsyncEnumerable.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace System.Linq
  10. {
  11. internal abstract class OrderedAsyncEnumerable<TElement> : AsyncEnumerable.AsyncIterator<TElement>, IOrderedAsyncEnumerable<TElement>
  12. {
  13. internal IOrderedEnumerable<TElement> enumerable;
  14. internal IAsyncEnumerable<TElement> source;
  15. IOrderedAsyncEnumerable<TElement> IOrderedAsyncEnumerable<TElement>.CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
  16. {
  17. return new OrderedAsyncEnumerable<TElement, TKey>(source, keySelector, comparer, descending, this);
  18. }
  19. internal abstract Task Initialize(CancellationToken cancellationToken);
  20. }
  21. internal sealed class OrderedAsyncEnumerable<TElement, TKey> : OrderedAsyncEnumerable<TElement>
  22. {
  23. private readonly IComparer<TKey> comparer;
  24. private readonly bool descending;
  25. private readonly Func<TElement, TKey> keySelector;
  26. private IEnumerator<TElement> enumerator;
  27. private readonly OrderedAsyncEnumerable<TElement> parent;
  28. private IAsyncEnumerator<TElement> parentEnumerator;
  29. public OrderedAsyncEnumerable(IAsyncEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, OrderedAsyncEnumerable<TElement> parent)
  30. {
  31. if (source == null) throw new ArgumentNullException(nameof(source));
  32. if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
  33. this.source = source;
  34. this.keySelector = keySelector;
  35. this.comparer = comparer ?? Comparer<TKey>.Default;
  36. this.descending = descending;
  37. this.parent = parent;
  38. }
  39. public override AsyncEnumerable.AsyncIterator<TElement> Clone()
  40. {
  41. return new OrderedAsyncEnumerable<TElement, TKey>(source, keySelector, comparer, descending, parent);
  42. }
  43. public override void Dispose()
  44. {
  45. if (enumerator != null)
  46. {
  47. enumerator.Dispose();
  48. enumerator = null;
  49. }
  50. if (parentEnumerator != null)
  51. {
  52. parentEnumerator.Dispose();
  53. parentEnumerator = null;
  54. }
  55. base.Dispose();
  56. }
  57. protected override async Task<bool> MoveNextCore(CancellationToken cancellationToken)
  58. {
  59. switch (state)
  60. {
  61. case AsyncEnumerable.AsyncIteratorState.Allocated:
  62. await Initialize(cancellationToken)
  63. .ConfigureAwait(false);
  64. enumerator = enumerable.GetEnumerator();
  65. state = AsyncEnumerable.AsyncIteratorState.Iterating;
  66. goto case AsyncEnumerable.AsyncIteratorState.Iterating;
  67. case AsyncEnumerable.AsyncIteratorState.Iterating:
  68. if (enumerator.MoveNext())
  69. {
  70. current = enumerator.Current;
  71. return true;
  72. }
  73. Dispose();
  74. break;
  75. }
  76. return false;
  77. }
  78. internal override async Task Initialize(CancellationToken cancellationToken)
  79. {
  80. if (parent == null)
  81. {
  82. var buffer = await source.ToList(cancellationToken)
  83. .ConfigureAwait(false);
  84. enumerable = (!@descending ? buffer.OrderBy(keySelector, comparer) : buffer.OrderByDescending(keySelector, comparer));
  85. }
  86. else
  87. {
  88. parentEnumerator = parent.GetEnumerator();
  89. await parent.Initialize(cancellationToken)
  90. .ConfigureAwait(false);
  91. enumerable = parent.enumerable.CreateOrderedEnumerable(keySelector, comparer, @descending);
  92. }
  93. }
  94. }
  95. }