|
@@ -4,11 +4,14 @@
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
using System.Reactive.Disposables;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
+using System.Runtime.ExceptionServices;
|
|
|
+using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace System.Reactive.Subjects
|
|
|
{
|
|
|
- public abstract class AsyncAsyncSubject<T> : IAsyncSubject<T>
|
|
|
+ public abstract class AsyncAsyncSubject<T> : IAsyncSubject<T>, INotifyCompletion
|
|
|
{
|
|
|
private readonly object _gate = new object();
|
|
|
private readonly List<IAsyncObserver<T>> _observers = new List<IAsyncObserver<T>>();
|
|
@@ -146,5 +149,90 @@ namespace System.Reactive.Subjects
|
|
|
return Task.CompletedTask;
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ public AsyncAsyncSubject<T> GetAwaiter() => this;
|
|
|
+
|
|
|
+ public bool IsCompleted => _done || _error != null;
|
|
|
+
|
|
|
+ public T GetResult()
|
|
|
+ {
|
|
|
+ if (!IsCompleted)
|
|
|
+ {
|
|
|
+ var e = new ManualResetEventSlim(initialState: false);
|
|
|
+
|
|
|
+ OnCompleted(() => { e.Set(); }, originalContext: false);
|
|
|
+
|
|
|
+ e.Wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_error != null)
|
|
|
+ {
|
|
|
+ ExceptionDispatchInfo.Capture(_error).Throw();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!_hasValue)
|
|
|
+ {
|
|
|
+ throw new InvalidOperationException("The subject has no value.");
|
|
|
+ }
|
|
|
+
|
|
|
+ return _value;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnCompleted(Action continuation)
|
|
|
+ {
|
|
|
+ if (continuation == null)
|
|
|
+ throw new ArgumentNullException(nameof(continuation));
|
|
|
+
|
|
|
+ OnCompleted(continuation, originalContext: true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnCompleted(Action continuation, bool originalContext)
|
|
|
+ {
|
|
|
+ var subscribeTask = SubscribeAsync(new AwaitObserver(continuation, originalContext));
|
|
|
+
|
|
|
+ subscribeTask.ContinueWith(t =>
|
|
|
+ {
|
|
|
+ if (t.Exception != null)
|
|
|
+ {
|
|
|
+ // TODO: Trace?
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private sealed class AwaitObserver : IAsyncObserver<T>
|
|
|
+ {
|
|
|
+ private readonly Action _continuation;
|
|
|
+ private readonly SynchronizationContext _context;
|
|
|
+
|
|
|
+ public AwaitObserver(Action continuation, bool originalContext)
|
|
|
+ {
|
|
|
+ _continuation = continuation;
|
|
|
+
|
|
|
+ if (originalContext)
|
|
|
+ {
|
|
|
+ _context = SynchronizationContext.Current;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task OnCompletedAsync() => InvokeAsync();
|
|
|
+
|
|
|
+ public Task OnErrorAsync(Exception error) => InvokeAsync();
|
|
|
+
|
|
|
+ public Task OnNextAsync(T value) => Task.CompletedTask;
|
|
|
+
|
|
|
+ private Task InvokeAsync()
|
|
|
+ {
|
|
|
+ if (_context != null)
|
|
|
+ {
|
|
|
+ _context.Post(c => ((Action)c)(), _continuation);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _continuation();
|
|
|
+ }
|
|
|
+
|
|
|
+ return Task.CompletedTask;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|