public static IObservable<Unit> WriteAsync(this Stream This, byte[] data, int start, int length) { var ret = new AsyncSubject<Unit>(); try { This.BeginWrite(data, start, length, result => { try { This.EndWrite(result); ret.OnNext(Unit.Default); ret.OnCompleted(); } catch (Exception ex) { ret.OnError(ex); } }, null); } catch (Exception ex) { ret.OnError(ex); } return ret; }
private IObservable<string> detect(string text) { var subject = new AsyncSubject<string>(); string detectUri = String.Format(GetDetectUri(text), appId, HttpUtility.HtmlEncode(text)); var wc = new WebClient(); wc.OpenReadCompleted += new OpenReadCompletedEventHandler((obj, args) => { if (args.Error != null) { subject.OnError(args.Error); } else { if (!args.Cancelled) { var xdoc = XDocument.Load(args.Result); subject.OnNext(xdoc.Root.Value); } subject.OnCompleted(); } }); wc.OpenReadAsync(new Uri(detectUri)); return subject; }
static async UniTaskVoid Fire(AsyncSubject <object> subject, UniTask task) { try { await task; subject.OnNext(null); subject.OnCompleted(); } catch (Exception ex) { subject.OnError(ex); } }
static async UniTaskVoid Fire <T>(AsyncSubject <T> subject, UniTask <T> task) { try { var value = await task; subject.OnNext(value); subject.OnCompleted(); } catch (Exception ex) { subject.OnError(ex); } }
public ObservableProcess(ProcessStartInfo startInfo, bool throwOnNonZeroExitCode = true) { startInfo.RedirectStandardError = startInfo.RedirectStandardOutput = startInfo.RedirectStandardInput = true; process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; process.OutputDataReceived += OnReceived; process.ErrorDataReceived += OnReceived; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); input = Observer.Create <string>( x => { process.StandardInput.WriteLine(x); process.StandardInput.Flush(); }, () => { }); Observable.Start(() => { int exitCode; try { process.WaitForExit(60 * 1000); } finally { // recreate flush logic from System.Diagnostics.Process WaitUntilEndOfFile("output"); WaitUntilEndOfFile("error"); exitCode = process.ExitCode; process.OutputDataReceived -= OnReceived; process.ErrorDataReceived -= OnReceived; process.Close(); } output.OnCompleted(); if (exitCode != 0 && throwOnNonZeroExitCode) { var error = string.Join("\n", output.ToArray().First()); exit.OnError(new Exception(error)); } else { exit.OnNext(exitCode); exit.OnCompleted(); } }, Scheduler.Default); }
public static IObservable <Stream> SafeOpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share, IScheduler?scheduler = null) { scheduler ??= BlobCache.TaskpoolScheduler; var ret = new AsyncSubject <Stream>(); Observable.Start( () => { try { var createModes = new[] { FileMode.Create, FileMode.CreateNew, FileMode.OpenOrCreate, }; // NB: We do this (even though it's incorrect!) because // throwing lots of 1st chance exceptions makes debugging // obnoxious, as well as a bug in VS where it detects // exceptions caught by Observable.Start as Unhandled. if (!createModes.Contains(mode) && !File.Exists(path)) { ret.OnError(new FileNotFoundException()); return; } Observable.Start(() => new FileStream(path, mode, access, share, 4096, false), scheduler).Cast <Stream>().Subscribe(ret); } catch (Exception ex) { ret.OnError(ex); } }, scheduler); return(ret); }
public static AsyncSubject <TSource> GetAwaiter <TSource, TException>(this IObservable <TSource> source, IObservable <TException> error, CancellationToken cancellationToken) where TException : Exception { if (source == null) { throw new ArgumentNullException("source"); } var s = new AsyncSubject <TSource>(); if (cancellationToken.IsCancellationRequested) { s.OnError(new OperationCanceledException(cancellationToken)); return(s); } var d1 = source.Subscribe(unit => { s.OnNext(unit); s.OnCompleted(); }, s.OnError, s.OnCompleted); var d2 = error.Subscribe(s.OnError); var d = StableCompositeDisposable.Create(d1, d2); if (cancellationToken.CanBeCanceled) { var ctr = cancellationToken.Register(() => { d.Dispose(); s.OnError(new OperationCanceledException(cancellationToken)); }); s.Subscribe(_ => { }, _ => ctr.Dispose(), ctr.Dispose); } return(s); }
/// <summary> /// Handler for unary response completion. /// </summary> private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) { // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT, // success will be always set to true. using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse")) { AsyncSubject <Unit> delayedStreamingWriteTcs = null; TResponse msg = default(TResponse); var deserializeException = TryDeserialize(receivedMessage, out msg); lock (myLock) { finished = true; if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK) { receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers); } finishedStatus = receivedStatus; if (isStreamingWriteCompletionDelayed) { delayedStreamingWriteTcs = streamingWriteTcs; streamingWriteTcs = null; } ReleaseResourcesIfPossible(); } responseHeadersTcs.OnNext(responseHeaders); responseHeadersTcs.OnCompleted(); if (delayedStreamingWriteTcs != null) { delayedStreamingWriteTcs.OnError(GetRpcExceptionClientOnly()); } var status = receivedStatus.Status; if (status.StatusCode != StatusCode.OK) { unaryResponseTcs.OnError(new RpcException(status, () => (finishedStatus.HasValue) ? GetTrailers() : null)); return; } unaryResponseTcs.OnNext(msg); unaryResponseTcs.OnCompleted(); } }
/// <summary> /// Writes to a stream and returns a observable. /// </summary> /// <param name="blobCache">The stream to write to.</param> /// <param name="data">The data to write.</param> /// <param name="start">The start location where to write from.</param> /// <param name="length">The length in bytes to read.</param> /// <returns>An observable that signals when the write operation has completed.</returns> public static IObservable <Unit> WriteAsyncRx(this Stream blobCache, byte[] data, int start, int length) { #if WINDOWS_UWP return(blobCache.WriteAsync(data, start, length).ToObservable()); #else var ret = new AsyncSubject <Unit>(); try { blobCache.BeginWrite( data, start, length, result => { try { blobCache.EndWrite(result); ret.OnNext(Unit.Default); ret.OnCompleted(); } catch (Exception ex) { ret.OnError(ex); } }, null); } catch (Exception ex) { ret.OnError(ex); } return(ret); #endif }
static async UniTaskVoid Fire(AsyncSubject <AsyncUnit> subject, UniTask task) { try { await task; } catch (Exception ex) { subject.OnError(ex); return; } subject.OnNext(AsyncUnit.Default); subject.OnCompleted(); }
private static IObservable <Unit> Observable <Unit>(this Task task) { AsyncSubject <Unit> sbj = new AsyncSubject <Unit>(); task.ContinueWith(t => { switch (t.Status) { case TaskStatus.RanToCompletion: sbj.OnCompleted(); break; case TaskStatus.Faulted: sbj.OnError(t.Exception.InnerException); break; case TaskStatus.Canceled: sbj.OnError(new TaskCanceledException(t)); break; } }, TaskContinuationOptions.ExecuteSynchronously); sbj.SubscribeConsole(); return(sbj.AsObservable()); }
public void sends_no_values_after_error() { AsyncSubject <int> subject = new AsyncSubject <int>(); StatsObserver <int> stats = new StatsObserver <int>(); subject.OnNext(1); subject.OnNext(2); subject.OnNext(3); subject.OnError(new Exception()); subject.Subscribe(stats); Assert.IsFalse(stats.NextCalled); Assert.IsFalse(stats.CompletedCalled); }
public void HasObservers_OnError() { var s = new AsyncSubject <int>(); Assert.IsFalse(s.HasObservers); var d = s.Subscribe(_ => { }, ex => { }); Assert.IsTrue(s.HasObservers); s.OnNext(42); Assert.IsTrue(s.HasObservers); s.OnError(new Exception()); Assert.IsFalse(s.HasObservers); }
public IObservable<TwitterSearchStatus> Search(string query, int page, int rpp) { var subject = new AsyncSubject<IEnumerable<TwitterSearchStatus>>(); this.service.Search(query, page, rpp, (tr, res) => { if (res.InnerException == null) { subject.OnNext(tr.Statuses); subject.OnCompleted(); } else { subject.OnError(res.InnerException); } }); return subject.AsObservable().SelectMany(r => r); }
public static IObservable <T> DoWorkAsync <T>(Func <T> work, IScheduler scheduler) { var asyncSubject = new AsyncSubject <T>(); Task.Factory.StartNew(() => { try { T result = work.Invoke(); asyncSubject.OnNext(result); asyncSubject.OnCompleted(); } catch (Exception e) { asyncSubject.OnError(e); } }); return(asyncSubject.ObserveOn(scheduler) .SubscribeOn(scheduler)); }
/// <summary> /// Handles streaming read completion. /// </summary> protected void HandleReadFinished(bool success, byte[] receivedMessage) { // if success == false, received message will be null. It that case we will // treat this completion as the last read an rely on C core to handle the failed // read (e.g. deliver approriate statusCode on the clientside). TRead msg = default(TRead); var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; AsyncSubject <TRead> origTcs = null; lock (myLock) { origTcs = streamingReadTcs; if (receivedMessage == null) { // This was the last read. readingDone = true; } if (deserializeException != null && IsClient) { readingDone = true; // TODO(jtattermusch): it might be too late to set the status CancelWithStatus(DeserializeResponseFailureStatus); } if (!readingDone) { streamingReadTcs = null; } ReleaseResourcesIfPossible(); } if (deserializeException != null && !IsClient) { origTcs.OnError(new IOException("Failed to deserialize request message.", deserializeException)); return; } origTcs.OnNext(msg); origTcs.OnCompleted(); }
public virtual AsyncSubject <TSource> RunAsync <TSource>(IConnectableObservable <TSource> source, CancellationToken cancellationToken) { var s = new AsyncSubject <TSource>(); var cancel = new Action(() => s.OnError(new OperationCanceledException())); if (cancellationToken.IsCancellationRequested) { cancel(); return(s); } var d = new CompositeDisposable(source.SubscribeSafe(s), source.Connect()); cancellationToken.Register(d.Dispose); cancellationToken.Register(cancel); return(s); }
public static IObservable <RestResponse <T> > RequestAsync <T>(this RestClient This, RestRequest request) { var ret = new AsyncSubject <RestResponse <T> >(); This.BeginRequest <T>(request, (rq, resp, state) => { try { ret.OnNext(resp); ret.OnCompleted(); } catch (Exception ex) { ret.OnError(ex); } }); return(ret); }
public virtual IObservable <bool> ConnectAsync(string serverAddress, string applicationName) { ValidateDisposed(); var future = new AsyncSubject <bool>(); var watchStatusChanged = new SingleAssignmentDisposable(); watchStatusChanged.Disposable = this.ObserveStatusChanged().Subscribe(x => { if (x == StatusCode.ExceptionOnConnect) { watchStatusChanged.Dispose(); future.OnError(new ConnectionFailedException(serverAddress, applicationName)); } if (x == StatusCode.Connect) { watchStatusChanged.Dispose(); future.OnNext(true); future.OnCompleted(); } }); if (this.Connect(serverAddress, applicationName)) { this.LastConnectServerAddress = serverAddress; this.LastConnectApplicationName = applicationName; return(future.Timeout(Timeout).Catch((Exception ex) => { watchStatusChanged.Dispose(); this.Disconnect(); return Observable.Throw <bool>(ex); })); } else { watchStatusChanged.Dispose(); return(Observable.Return(false)); } }
/// <summary> /// Invalidates all objects of the specified type. To invalidate all /// objects regardless of type, use InvalidateAll. /// </summary> /// <remarks>Returns a Unit for each invalidation completion. Use Wait instead of First to wait for /// this.</remarks> public static IObservable <Unit> InvalidateAllObjects <T>(this IBlobCache This) { var objCache = This as IObjectBlobCache; if (objCache != null) { return(objCache.InvalidateAllObjects <T>()); } var ret = new AsyncSubject <Unit>(); This.GetAllKeys().Where(x => x.StartsWith(GetTypePrefixedKey("", typeof(T)))) .ToObservable() .SelectMany(This.Invalidate) .Subscribe( _ => { }, ex => ret.OnError(ex), () => { ret.OnNext(Unit.Default); ret.OnCompleted(); }); return(ret); }
/* Getting from A to B: * * This is what it might look like if we wrapped this method by-hand. Writing * this code over and over again would get really boring, but it's good to do it * once to see what it would look like. */ public static IObservable <string> DownloadPageTextRx(string url) { var subject = new AsyncSubject <string>(); // Call our original method try { DownloadPageTextAsync(url, (pageText) => { subject.OnNext(pageText); subject.OnCompleted(); }); } catch (Exception ex) { subject.OnError(ex); } return(subject); }
IObservable <T> SafeStart <T>(Func <T> calculationFunc) { var ret = new AsyncSubject <T>(); Observable.Start(() => { try { var val = calculationFunc(); ret.OnNext(val); ret.OnCompleted(); } catch (Exception ex) { this.Log().WarnException("Failure running queued op", ex); ret.OnError(ex); } }, scheduler); return(ret); }
public static IObservable <TResult> StartAsync <TResult>(Func <CancellationToken, Task <TResult> > functionAsync, IScheduler scheduler) { var subject = new AsyncSubject <TResult>(); scheduler.Schedule(() => { var cancellable = new CancellationDisposable(); var task = default(Task <TResult>); try { task = functionAsync(cancellable.Token); } catch (Exception exception) { subject.OnError(exception); } var disp = task.ToObservable().Subscribe(subject); }); return(subject.AsObservable()); }
/* Now, let's make this really generic - let's wrap *any* method that takes one * parameter. We could write really similar versions of this for 2,3,4,etc * parameter methods */ public static Func <T1, IObservable <TRet> > FromCallbackPattern <T1, TRet>(Action <T1, Action <TRet> > originalMethod) { return(param1 => { var subject = new AsyncSubject <TRet>(); try { originalMethod(param1, (result) => { subject.OnNext(result); subject.OnCompleted(); }); } catch (Exception ex) { subject.OnError(ex); } return subject; }); }
public static IObservable <T> ReturnAsync <T>( Func <T> factory, IScheduler scheduler = null) { scheduler = scheduler ?? Scheduler.Default; AsyncSubject <T> res = new AsyncSubject <T>(); scheduler.Schedule(() => { try { res.OnNext(factory()); res.OnCompleted(); } catch (Exception ex) { res.OnError(ex); } }); return(res); }
public virtual IObservable <bool> EstablishEncryptionAsync() { ValidateDisposed(); var future = new AsyncSubject <bool>(); var watchStatusChanged = new SingleAssignmentDisposable(); watchStatusChanged.Disposable = this.ObserveStatusChanged().Subscribe(x => { if (x == StatusCode.EncryptionFailedToEstablish) { watchStatusChanged.Dispose(); future.OnError(new EncryptionFailedToEstablishException()); } if (x == StatusCode.EncryptionEstablished) { watchStatusChanged.Dispose(); future.OnNext(true); future.OnCompleted(); } }); if (this.EstablishEncryption()) { return(future.Timeout(Timeout).Catch((Exception ex) => { watchStatusChanged.Dispose(); this.Disconnect(); return Observable.Throw <bool>(ex); })); } else { watchStatusChanged.Dispose(); return(Observable.Return(false)); } }
/// <summary> /// WebContextのログインを行う。 /// </summary> /// <param name="self"></param> /// <param name="userName">ユーザ名</param> /// <param name="password">パスワード</param> /// <returns>ユーザ情報。ログインできていない場合はnull。</returns> public static IObservable<User> LoginAsObservable(this WebContext self, string userName, string password) { // Subscribeまで処理を遅延させるためDeferでくるむ return Observable.Defer(() => { var async = new AsyncSubject<User>(); // ログインを行う var op = self.Authentication.Login(userName, password); // Completedイベントを購読して Observable.FromEvent<EventHandler, EventArgs>( h => (s, e) => h(e), h => op.Completed += h, h => op.Completed -= h) // 1回のイベント発火でイベントハンドラを解除する .Take(1) .Subscribe(_ => { // キャンセルされてたら何もせず終了 if (op.IsCanceled) { async.OnCompleted(); return; } // エラーの場合はエラー通知 if (op.HasError) { op.MarkErrorAsHandled(); async.OnError(op.Error); return; } // ユーザ情報を発行して終了。 async.OnNext(op.User as User); async.OnCompleted(); }); return async.AsObservable(); }); }
protected override IObservable <Unit> CheckSendAllowedOrEarlyResult() { var earlyResult = CheckSendPreconditionsClientSide(); if (earlyResult != null) { return(earlyResult); } if (finishedStatus.HasValue) { // throwing RpcException if we already received status on client // side makes the most sense. // Note that this throws even for StatusCode.OK. // Writing after the call has finished is not a programming error because server can close // the call anytime, so don't throw directly, but let the write task finish with an error. var tcs = new AsyncSubject <Unit>(); tcs.OnError(new RpcException(finishedStatus.Value.Status, () => (finishedStatus.HasValue) ? GetTrailers() : null)); return(tcs); } return(null); }
public static Func <IObservable <Unit> > ToAsync(Action action, IScheduler scheduler) { return(() => { var subject = new AsyncSubject <Unit>(); scheduler.Schedule(() => { try { action(); } catch (Exception exception) { subject.OnError(exception); return; } subject.OnNext(Unit.Default); subject.OnCompleted(); }); return subject.AsObservable(); }); }
public static Func <T1, T2, IObservable <Unit> > FromAsyncPattern <T1, T2>(Func <T1, T2, AsyncCallback, object, IAsyncResult> begin, Action <IAsyncResult> end) { return((t1, t2) => { var future = new AsyncSubject <Unit>(); begin(t1, t2, ar => { try { end(ar); } catch (Exception ex) { future.OnError(ex); return; } future.OnNext(Unit.Default); future.OnCompleted(); }, null); return future; }); }
private void GetResult_Blocking_Throw(AsyncSubject <int> s) { Assert.IsFalse(s.IsCompleted); var e = new ManualResetEvent(false); var ex = new Exception(); new Thread(() => { e.WaitOne(); s.OnError(ex); }).Start(); var y = default(Exception); var t = new Thread(() => { try { s.GetResult(); } catch (Exception ex_) { y = ex_; } }); t.Start(); while (t.ThreadState != ThreadState.WaitSleepJoin) { ; } e.Set(); t.Join(); Assert.AreSame(ex, y); Assert.IsTrue(s.IsCompleted); }
/// <summary> /// Handles receive status completion for calls with streaming response. /// </summary> private void HandleFinished(bool success, ClientSideStatus receivedStatus) { // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT, // success will be always set to true. AsyncSubject <Unit> delayedStreamingWriteTcs = null; lock (myLock) { finished = true; finishedStatus = receivedStatus; if (isStreamingWriteCompletionDelayed) { delayedStreamingWriteTcs = streamingWriteTcs; streamingWriteTcs = null; } ReleaseResourcesIfPossible(); } if (delayedStreamingWriteTcs != null) { delayedStreamingWriteTcs.OnError(GetRpcExceptionClientOnly()); } var status = receivedStatus.Status; if (status.StatusCode != StatusCode.OK) { streamingCallFinishedTcs.OnError(new RpcException(status, () => (finishedStatus.HasValue) ? GetTrailers() : null)); return; } streamingCallFinishedTcs.OnNext(null); streamingCallFinishedTcs.OnCompleted(); }
public static IObservable<NameResolutionResult> ResolveHostName(DnsEndPoint endPoint, NetworkInterfaceInfo networkInterface) { Contract.Requires(endPoint != null); Contract.Requires(networkInterface != null); Contract.Ensures(Contract.Result<IObservable<NameResolutionResult>>() != null); var subject = new AsyncSubject<NameResolutionResult>(); try { DeviceNetworkInformation.ResolveHostNameAsync( endPoint, networkInterface, result => { var s = (AsyncSubject<NameResolutionResult>) result.AsyncState; s.OnNext(result); s.OnCompleted(); }, subject); } catch (Exception ex) { subject.OnError(ex); } return subject.AsObservable(); }
public virtual IObservable<bool> EstablishEncryptionAsync() { ValidateDisposed(); var future = new AsyncSubject<bool>(); var watchStatusChanged = new SingleAssignmentDisposable(); watchStatusChanged.Disposable = this.ObserveStatusChanged().Subscribe(x => { if (x == StatusCode.EncryptionFailedToEstablish) { watchStatusChanged.Dispose(); future.OnError(new EncryptionFailedToEstablishException()); } if (x == StatusCode.EncryptionEstablished) { watchStatusChanged.Dispose(); future.OnNext(true); future.OnCompleted(); } }); if (this.EstablishEncryption()) { return future.Timeout(Timeout).Catch((Exception ex) => { watchStatusChanged.Dispose(); this.Disconnect(); return Observable.Throw<bool>(ex); }); } else { watchStatusChanged.Dispose(); return Observable.Return(false); } }
public virtual IObservable<bool> ConnectAsync(string serverAddress, string applicationName) { ValidateDisposed(); var future = new AsyncSubject<bool>(); var watchStatusChanged = new SingleAssignmentDisposable(); watchStatusChanged.Disposable = this.ObserveStatusChanged().Subscribe(x => { if (x == StatusCode.ExceptionOnConnect) { watchStatusChanged.Dispose(); future.OnError(new ConnectionFailedException(serverAddress, applicationName)); } if (x == StatusCode.Connect) { watchStatusChanged.Dispose(); future.OnNext(true); future.OnCompleted(); } }); if (this.Connect(serverAddress, applicationName)) { this.LastConnectServerAddress = serverAddress; this.LastConnectApplicationName = applicationName; return future.Timeout(Timeout).Catch((Exception ex) => { watchStatusChanged.Dispose(); this.Disconnect(); return Observable.Throw<bool>(ex); }); } else { watchStatusChanged.Dispose(); return Observable.Return(false); } }
public IObservable<Unit> QueueBackgroundDownloads(IEnumerable<string> urls, IEnumerable<string> localPaths) { var ret = new AsyncSubject<Unit>(); var jobFiles = urls.Zip(localPaths, (url, path) => new {url, path}); var job = manager.CreateJob(applicationName + "_" + Guid.NewGuid() , JobType.Download); job.OnJobError += (o, e) => ret.OnError(new BitsException(e.Error)); job.OnJobTransferred += (o, e) => { try { job.Complete(); if (job.ErrorCount != 0) { ret.OnError(new BitsException(job.Error)); } else { ret.OnNext(Unit.Default); ret.OnCompleted(); } } catch (Exception ex) { ret.OnError(ex); } }; jobFiles .Where(x => !File.Exists(x.path)) .ForEach(x => job.AddFile(x.url, x.path)); job.Resume(); return ret; }
public void OnError(Exception error) { subject.OnError(error); }
public void sends_no_values_after_error() { AsyncSubject<int> subject = new AsyncSubject<int>(); StatsObserver<int> stats = new StatsObserver<int>(); subject.OnNext(1); subject.OnNext(2); subject.OnNext(3); subject.OnError(new Exception()); subject.Subscribe(stats); Assert.IsFalse(stats.NextCalled); Assert.IsFalse(stats.CompletedCalled); }
public void HasObservers_OnError() { var s = new AsyncSubject<int>(); Assert.IsFalse(s.HasObservers); var d = s.Subscribe(_ => { }, ex => { }); Assert.IsTrue(s.HasObservers); s.OnNext(42); Assert.IsTrue(s.HasObservers); s.OnError(new Exception()); Assert.IsFalse(s.HasObservers); }
private void GetResult_Blocking_Throw(AsyncSubject<int> s) { Assert.IsFalse(s.IsCompleted); var e = new ManualResetEvent(false); var ex = new Exception(); new Thread(() => { e.WaitOne(); s.OnError(ex); }).Start(); var y = default(Exception); var t = new Thread(() => { try { s.GetResult(); } catch (Exception ex_) { y = ex_; } }); t.Start(); while (t.ThreadState != ThreadState.WaitSleepJoin) ; e.Set(); t.Join(); Assert.AreSame(ex, y); Assert.IsTrue(s.IsCompleted); }
public void AsyncSubjectTest() { // OnCompletedPattern { var subject = new AsyncSubject<int>(); var onNext = new List<int>(); var exception = new List<Exception>(); int onCompletedCallCount = 0; subject.Subscribe(x => onNext.Add(x), x => exception.Add(x), () => onCompletedCallCount++); subject.OnNext(1); subject.OnNext(10); subject.OnNext(100); subject.OnNext(1000); onNext.Count.Is(0); subject.OnCompleted(); onNext.IsCollection(1000); onCompletedCallCount.Is(1); subject.OnNext(1); subject.OnNext(10); subject.OnNext(100); onNext.Count.Is(1); subject.OnCompleted(); subject.OnError(new Exception()); exception.Count.Is(0); onCompletedCallCount.Is(1); // ++subscription subject.Subscribe(x => onNext.Add(x), x => exception.Add(x), () => onCompletedCallCount++); onNext.IsCollection(1000, 1000); exception.Count.Is(0); onCompletedCallCount.Is(2); } // OnErrorPattern { var subject = new AsyncSubject<int>(); var onNext = new List<int>(); var exception = new List<Exception>(); int onCompletedCallCount = 0; subject.Subscribe(x => onNext.Add(x), x => exception.Add(x), () => onCompletedCallCount++); subject.OnNext(1); subject.OnNext(10); subject.OnNext(100); subject.OnNext(1000); onNext.Count.Is(0); subject.OnError(new Exception()); exception.Count.Is(1); subject.OnNext(1); subject.OnNext(10); subject.OnNext(100); onNext.Count.Is(0); subject.OnCompleted(); subject.OnError(new Exception()); exception.Count.Is(1); onCompletedCallCount.Is(0); // ++subscription subject.Subscribe(x => onNext.Add(x), x => exception.Add(x), () => onCompletedCallCount++); onNext.Count.Is(0); exception.Count.Is(2); onCompletedCallCount.Is(0); } }
void IObserver <AssetBundle> .OnError(Exception error) => subject.OnError(error);