Except.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. public static partial class AsyncEnumerable
  12. {
  13. public static IAsyncEnumerable<TSource> Except<TSource>(this IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second)
  14. {
  15. if (first == null)
  16. throw new ArgumentNullException(nameof(first));
  17. if (second == null)
  18. throw new ArgumentNullException(nameof(second));
  19. return first.Except(second, EqualityComparer<TSource>.Default);
  20. }
  21. public static IAsyncEnumerable<TSource> Except<TSource>(this IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
  22. {
  23. if (first == null)
  24. throw new ArgumentNullException(nameof(first));
  25. if (second == null)
  26. throw new ArgumentNullException(nameof(second));
  27. if (comparer == null)
  28. throw new ArgumentNullException(nameof(comparer));
  29. return Create(() =>
  30. {
  31. var e = first.GetEnumerator();
  32. var cts = new CancellationTokenDisposable();
  33. var d = Disposable.Create(cts, e);
  34. var mapTask = default(Task<Dictionary<TSource, TSource>>);
  35. var getMapTask = new Func<CancellationToken, Task<Dictionary<TSource, TSource>>>(
  36. ct => mapTask ?? (mapTask = second.ToDictionary(x => x, comparer, ct)));
  37. var f = default(Func<CancellationToken, Task<bool>>);
  38. f = async ct =>
  39. {
  40. if (await e.MoveNext(ct)
  41. .Zip(getMapTask(ct), (b, _) => b)
  42. .ConfigureAwait(false))
  43. {
  44. if (!mapTask.Result.ContainsKey(e.Current))
  45. return true;
  46. return await f(ct)
  47. .ConfigureAwait(false);
  48. }
  49. return false;
  50. };
  51. return Create(
  52. f,
  53. () => e.Current,
  54. d.Dispose,
  55. e
  56. );
  57. });
  58. }
  59. }
  60. }