OrderedAsyncEnumerable.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace System.Linq
  9. {
  10. internal abstract class OrderedAsyncEnumerable<TElement> : AsyncEnumerable.AsyncIterator<TElement>, IOrderedAsyncEnumerable<TElement>
  11. {
  12. internal IOrderedEnumerable<TElement> enumerable;
  13. internal IAsyncEnumerable<TElement> source;
  14. IOrderedAsyncEnumerable<TElement> IOrderedAsyncEnumerable<TElement>.CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
  15. {
  16. return new OrderedAsyncEnumerable<TElement, TKey>(source, keySelector, comparer, descending, this);
  17. }
  18. internal abstract Task Initialize(CancellationToken cancellationToken);
  19. }
  20. internal sealed class OrderedAsyncEnumerable<TElement, TKey> : OrderedAsyncEnumerable<TElement>
  21. {
  22. private readonly IComparer<TKey> comparer;
  23. private readonly bool descending;
  24. private readonly Func<TElement, TKey> keySelector;
  25. private readonly OrderedAsyncEnumerable<TElement> parent;
  26. private IEnumerator<TElement> enumerator;
  27. private IAsyncEnumerator<TElement> parentEnumerator;
  28. public OrderedAsyncEnumerable(IAsyncEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, OrderedAsyncEnumerable<TElement> parent)
  29. {
  30. Debug.Assert(source != null);
  31. Debug.Assert(keySelector != null);
  32. Debug.Assert(comparer != null);
  33. this.source = source;
  34. this.keySelector = keySelector;
  35. this.comparer = comparer;
  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. }