TaskAwaitable.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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.Reactive.Concurrency;
  5. using System.Runtime.CompilerServices;
  6. namespace System.Threading.Tasks
  7. {
  8. public sealed class TaskAwaitable : IAwaitable, IAwaiter
  9. {
  10. private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _task;
  11. private readonly IAsyncScheduler _scheduler;
  12. private readonly CancellationToken _token;
  13. public TaskAwaitable(Task task, IAsyncScheduler scheduler, CancellationToken token)
  14. {
  15. _task = task.ConfigureAwait(false).GetAwaiter();
  16. _scheduler = scheduler;
  17. _token = token;
  18. }
  19. public bool IsCompleted => _task.IsCompleted;
  20. public IAwaiter GetAwaiter() => this;
  21. public void GetResult()
  22. {
  23. _token.ThrowIfCancellationRequested();
  24. _task.GetResult();
  25. }
  26. public void OnCompleted(Action continuation)
  27. {
  28. var cancel = default(IDisposable);
  29. if (_token.CanBeCanceled)
  30. {
  31. cancel = _token.Register(() =>
  32. {
  33. Interlocked.Exchange(ref continuation, null)?.Invoke();
  34. });
  35. }
  36. try
  37. {
  38. _task.OnCompleted(() =>
  39. {
  40. var t = _scheduler.ExecuteAsync(ct =>
  41. {
  42. cancel?.Dispose();
  43. Interlocked.Exchange(ref continuation, null)?.Invoke();
  44. return Task.CompletedTask;
  45. }, _token);
  46. });
  47. }
  48. catch
  49. {
  50. cancel?.Dispose();
  51. throw;
  52. }
  53. }
  54. }
  55. public sealed class TaskAwaitable<T> : IAwaitable<T>, IAwaiter<T>
  56. {
  57. private readonly ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter _task;
  58. private readonly IAsyncScheduler _scheduler;
  59. private readonly CancellationToken _token;
  60. public TaskAwaitable(Task<T> task, IAsyncScheduler scheduler, CancellationToken token)
  61. {
  62. _task = task.ConfigureAwait(false).GetAwaiter();
  63. _scheduler = scheduler;
  64. _token = token;
  65. }
  66. public bool IsCompleted => _task.IsCompleted;
  67. public IAwaiter<T> GetAwaiter() => this;
  68. public T GetResult()
  69. {
  70. _token.ThrowIfCancellationRequested();
  71. return _task.GetResult();
  72. }
  73. public void OnCompleted(Action continuation)
  74. {
  75. var cancel = default(IDisposable);
  76. if (_token.CanBeCanceled)
  77. {
  78. cancel = _token.Register(() =>
  79. {
  80. Interlocked.Exchange(ref continuation, null)?.Invoke();
  81. });
  82. }
  83. try
  84. {
  85. _task.OnCompleted(() =>
  86. {
  87. var t = _scheduler.ExecuteAsync(ct =>
  88. {
  89. cancel?.Dispose();
  90. Interlocked.Exchange(ref continuation, null)?.Invoke();
  91. return Task.CompletedTask;
  92. }, _token);
  93. });
  94. }
  95. catch
  96. {
  97. cancel?.Dispose();
  98. throw;
  99. }
  100. }
  101. }
  102. }