Notification.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  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.Globalization;
  7. using System.Runtime.ExceptionServices;
  8. using System.Threading.Tasks;
  9. #pragma warning disable 0659
  10. #pragma warning disable 0661
  11. namespace System.Reactive
  12. {
  13. /// <summary>
  14. /// Indicates the type of a notification.
  15. /// </summary>
  16. public enum NotificationKind
  17. {
  18. /// <summary>
  19. /// Represents an OnNext notification.
  20. /// </summary>
  21. OnNext,
  22. /// <summary>
  23. /// Represents an OnError notification.
  24. /// </summary>
  25. OnError,
  26. /// <summary>
  27. /// Represents an OnCompleted notification.
  28. /// </summary>
  29. OnCompleted,
  30. }
  31. /// <summary>
  32. /// Represents a notification to an observer.
  33. /// </summary>
  34. /// <typeparam name="T">The type of the elements received by the observer.</typeparam>
  35. #if !NO_SERIALIZABLE
  36. [Serializable]
  37. #endif
  38. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2218:OverrideGetHashCodeOnOverridingEquals", Justification = "Resembles a discriminated union with finite number of subclasses (external users shouldn't create their own subtypes), each of which does override GetHashCode itself.")]
  39. public abstract class Notification<T> : IEquatable<Notification<T>>
  40. {
  41. /// <summary>
  42. /// Default constructor used by derived types.
  43. /// </summary>
  44. protected internal Notification()
  45. {
  46. }
  47. /// <summary>
  48. /// Returns the value of an OnNext notification or throws an exception.
  49. /// </summary>
  50. public abstract T Value { get; }
  51. /// <summary>
  52. /// Returns a value that indicates whether the notification has a value.
  53. /// </summary>
  54. public abstract bool HasValue { get; }
  55. /// <summary>
  56. /// Returns the exception of an OnError notification or returns <c>null</c>.
  57. /// </summary>
  58. public abstract Exception Exception { get; }
  59. /// <summary>
  60. /// Gets the kind of notification that is represented.
  61. /// </summary>
  62. public abstract NotificationKind Kind { get; }
  63. /// <summary>
  64. /// Represents an OnNext notification to an observer.
  65. /// </summary>
  66. #if !NO_DEBUGGER_ATTRIBUTES
  67. [DebuggerDisplay("OnNext({Value})")]
  68. #endif
  69. #if !NO_SERIALIZABLE
  70. [Serializable]
  71. #endif
  72. internal sealed class OnNextNotification : Notification<T>
  73. {
  74. /// <summary>
  75. /// Constructs a notification of a new value.
  76. /// </summary>
  77. public OnNextNotification(T value)
  78. {
  79. Value = value;
  80. }
  81. /// <summary>
  82. /// Returns the value of an OnNext notification.
  83. /// </summary>
  84. public override T Value { get; }
  85. /// <summary>
  86. /// Returns <c>null</c>.
  87. /// </summary>
  88. public override Exception Exception => null;
  89. /// <summary>
  90. /// Returns <c>true</c>.
  91. /// </summary>
  92. public override bool HasValue => true;
  93. /// <summary>
  94. /// Returns <see cref="NotificationKind.OnNext"/>.
  95. /// </summary>
  96. public override NotificationKind Kind => NotificationKind.OnNext;
  97. /// <summary>
  98. /// Returns the hash code for this instance.
  99. /// </summary>
  100. public override int GetHashCode() => EqualityComparer<T>.Default.GetHashCode(Value);
  101. /// <summary>
  102. /// Indicates whether this instance and a specified object are equal.
  103. /// </summary>
  104. public override bool Equals(Notification<T> other)
  105. {
  106. if (ReferenceEquals(this, other))
  107. return true;
  108. if (ReferenceEquals(other, null))
  109. return false;
  110. if (other.Kind != NotificationKind.OnNext)
  111. return false;
  112. return EqualityComparer<T>.Default.Equals(Value, other.Value);
  113. }
  114. /// <summary>
  115. /// Returns a string representation of this instance.
  116. /// </summary>
  117. public override string ToString() => String.Format(CultureInfo.CurrentCulture, "OnNext({0})", Value);
  118. /// <summary>
  119. /// Invokes the observer's method corresponding to the notification.
  120. /// </summary>
  121. /// <param name="observer">Observer to invoke the notification on.</param>
  122. public override void Accept(IObserver<T> observer)
  123. {
  124. if (observer == null)
  125. throw new ArgumentNullException(nameof(observer));
  126. observer.OnNext(Value);
  127. }
  128. /// <summary>
  129. /// Invokes the observer's method corresponding to the notification.
  130. /// </summary>
  131. /// <param name="observer">Observer to invoke the notification on.</param>
  132. /// <returns>Task indicating the completion of invoking the observer method.</returns>
  133. public override Task AcceptAsync(IAsyncObserver<T> observer)
  134. {
  135. if (observer == null)
  136. throw new ArgumentNullException(nameof(observer));
  137. return observer.OnNextAsync(Value);
  138. }
  139. #if NOTYET
  140. /// <summary>
  141. /// Invokes the observer's method corresponding to the notification and returns the produced result.
  142. /// </summary>
  143. /// <param name="observer">Observer to invoke the notification on.</param>
  144. /// <returns>Result produced by the observation.</returns>
  145. public override TResult Accept<TResult>(IObserver<T, TResult> observer)
  146. {
  147. if (observer == null)
  148. throw new ArgumentNullException(nameof(observer));
  149. return observer.OnNext(Value);
  150. }
  151. #endif
  152. /// <summary>
  153. /// Invokes the delegate corresponding to the notification.
  154. /// </summary>
  155. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  156. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  157. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  158. public override void Accept(Action<T> onNext, Action<Exception> onError, Action onCompleted)
  159. {
  160. if (onNext == null)
  161. throw new ArgumentNullException(nameof(onNext));
  162. if (onError == null)
  163. throw new ArgumentNullException(nameof(onError));
  164. if (onCompleted == null)
  165. throw new ArgumentNullException(nameof(onCompleted));
  166. onNext(Value);
  167. }
  168. /// <summary>
  169. /// Invokes the delegate corresponding to the notification and returns the produced result.
  170. /// </summary>
  171. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  172. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  173. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  174. /// <returns>Result produced by the observation.</returns>
  175. public override TResult Accept<TResult>(Func<T, TResult> onNext, Func<Exception, TResult> onError, Func<TResult> onCompleted)
  176. {
  177. if (onNext == null)
  178. throw new ArgumentNullException(nameof(onNext));
  179. if (onError == null)
  180. throw new ArgumentNullException(nameof(onError));
  181. if (onCompleted == null)
  182. throw new ArgumentNullException(nameof(onCompleted));
  183. return onNext(Value);
  184. }
  185. /// <summary>
  186. /// Invokes the delegate corresponding to the notification.
  187. /// </summary>
  188. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  189. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  190. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  191. /// <returns>Task indicating the completion of invoking the delegate.</returns>
  192. public override Task AcceptAsync(Func<T, Task> onNext, Func<Exception, Task> onError, Func<Task> onCompleted)
  193. {
  194. if (onNext == null)
  195. throw new ArgumentNullException(nameof(onNext));
  196. if (onError == null)
  197. throw new ArgumentNullException(nameof(onError));
  198. if (onCompleted == null)
  199. throw new ArgumentNullException(nameof(onCompleted));
  200. return onNext(Value);
  201. }
  202. /// <summary>
  203. /// Invokes the delegate corresponding to the notification and returns the produced result.
  204. /// </summary>
  205. /// <typeparam name="TResult">The type of the result returned from the notification handler delegates.</typeparam>
  206. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  207. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  208. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  209. /// <returns>Task containing the result produced by the observation.</returns>
  210. public override Task<TResult> AcceptAsync<TResult>(Func<T, Task<TResult>> onNext, Func<Exception, Task<TResult>> onError, Func<Task<TResult>> onCompleted)
  211. {
  212. if (onNext == null)
  213. throw new ArgumentNullException(nameof(onNext));
  214. if (onError == null)
  215. throw new ArgumentNullException(nameof(onError));
  216. if (onCompleted == null)
  217. throw new ArgumentNullException(nameof(onCompleted));
  218. return onNext(Value);
  219. }
  220. }
  221. /// <summary>
  222. /// Represents an OnError notification to an observer.
  223. /// </summary>
  224. #if !NO_DEBUGGER_ATTRIBUTES
  225. [DebuggerDisplay("OnError({Exception})")]
  226. #endif
  227. #if !NO_SERIALIZABLE
  228. [Serializable]
  229. #endif
  230. internal sealed class OnErrorNotification : Notification<T>
  231. {
  232. /// <summary>
  233. /// Constructs a notification of an exception.
  234. /// </summary>
  235. public OnErrorNotification(Exception exception)
  236. {
  237. Exception = exception;
  238. }
  239. /// <summary>
  240. /// Throws the exception.
  241. /// </summary>
  242. public override T Value { get { ExceptionDispatchInfo.Capture(Exception).Throw(); return default(T); } }
  243. /// <summary>
  244. /// Returns the exception.
  245. /// </summary>
  246. public override Exception Exception { get; }
  247. /// <summary>
  248. /// Returns <c>false</c>.
  249. /// </summary>
  250. public override bool HasValue => false;
  251. /// <summary>
  252. /// Returns <see cref="NotificationKind.OnError"/>.
  253. /// </summary>
  254. public override NotificationKind Kind => NotificationKind.OnError;
  255. /// <summary>
  256. /// Returns the hash code for this instance.
  257. /// </summary>
  258. public override int GetHashCode() => Exception.GetHashCode();
  259. /// <summary>
  260. /// Indicates whether this instance and other are equal.
  261. /// </summary>
  262. public override bool Equals(Notification<T> other)
  263. {
  264. if (ReferenceEquals(this, other))
  265. return true;
  266. if (ReferenceEquals(other, null))
  267. return false;
  268. if (other.Kind != NotificationKind.OnError)
  269. return false;
  270. return Equals(Exception, other.Exception);
  271. }
  272. /// <summary>
  273. /// Returns a string representation of this instance.
  274. /// </summary>
  275. public override string ToString() => String.Format(CultureInfo.CurrentCulture, "OnError({0})", Exception.GetType().FullName);
  276. /// <summary>
  277. /// Invokes the observer's method corresponding to the notification.
  278. /// </summary>
  279. /// <param name="observer">Observer to invoke the notification on.</param>
  280. public override void Accept(IObserver<T> observer)
  281. {
  282. if (observer == null)
  283. throw new ArgumentNullException(nameof(observer));
  284. observer.OnError(Exception);
  285. }
  286. /// <summary>
  287. /// Invokes the observer's method corresponding to the notification.
  288. /// </summary>
  289. /// <param name="observer">Observer to invoke the notification on.</param>
  290. /// <returns>Task indicating the completion of invoking the observer method.</returns>
  291. public override Task AcceptAsync(IAsyncObserver<T> observer)
  292. {
  293. if (observer == null)
  294. throw new ArgumentNullException(nameof(observer));
  295. return observer.OnErrorAsync(Exception);
  296. }
  297. #if NOTYET
  298. /// <summary>
  299. /// Invokes the observer's method corresponding to the notification and returns the produced result.
  300. /// </summary>
  301. /// <param name="observer">Observer to invoke the notification on.</param>
  302. /// <returns>Result produced by the observation.</returns>
  303. public override TResult Accept<TResult>(IObserver<T, TResult> observer)
  304. {
  305. if (observer == null)
  306. throw new ArgumentNullException(nameof(observer));
  307. return observer.OnError(Exception);
  308. }
  309. #endif
  310. /// <summary>
  311. /// Invokes the delegate corresponding to the notification.
  312. /// </summary>
  313. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  314. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  315. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  316. public override void Accept(Action<T> onNext, Action<Exception> onError, Action onCompleted)
  317. {
  318. if (onNext == null)
  319. throw new ArgumentNullException(nameof(onNext));
  320. if (onError == null)
  321. throw new ArgumentNullException(nameof(onError));
  322. if (onCompleted == null)
  323. throw new ArgumentNullException(nameof(onCompleted));
  324. onError(Exception);
  325. }
  326. /// <summary>
  327. /// Invokes the delegate corresponding to the notification and returns the produced result.
  328. /// </summary>
  329. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  330. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  331. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  332. /// <returns>Result produced by the observation.</returns>
  333. public override TResult Accept<TResult>(Func<T, TResult> onNext, Func<Exception, TResult> onError, Func<TResult> onCompleted)
  334. {
  335. if (onNext == null)
  336. throw new ArgumentNullException(nameof(onNext));
  337. if (onError == null)
  338. throw new ArgumentNullException(nameof(onError));
  339. if (onCompleted == null)
  340. throw new ArgumentNullException(nameof(onCompleted));
  341. return onError(Exception);
  342. }
  343. /// <summary>
  344. /// Invokes the delegate corresponding to the notification.
  345. /// </summary>
  346. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  347. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  348. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  349. /// <returns>Task indicating the completion of invoking the delegate.</returns>
  350. public override Task AcceptAsync(Func<T, Task> onNext, Func<Exception, Task> onError, Func<Task> onCompleted)
  351. {
  352. if (onNext == null)
  353. throw new ArgumentNullException(nameof(onNext));
  354. if (onError == null)
  355. throw new ArgumentNullException(nameof(onError));
  356. if (onCompleted == null)
  357. throw new ArgumentNullException(nameof(onCompleted));
  358. return onError(Exception);
  359. }
  360. /// <summary>
  361. /// Invokes the delegate corresponding to the notification and returns the produced result.
  362. /// </summary>
  363. /// <typeparam name="TResult">The type of the result returned from the notification handler delegates.</typeparam>
  364. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  365. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  366. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  367. /// <returns>Task containing the result produced by the observation.</returns>
  368. public override Task<TResult> AcceptAsync<TResult>(Func<T, Task<TResult>> onNext, Func<Exception, Task<TResult>> onError, Func<Task<TResult>> onCompleted)
  369. {
  370. if (onNext == null)
  371. throw new ArgumentNullException(nameof(onNext));
  372. if (onError == null)
  373. throw new ArgumentNullException(nameof(onError));
  374. if (onCompleted == null)
  375. throw new ArgumentNullException(nameof(onCompleted));
  376. return onError(Exception);
  377. }
  378. }
  379. /// <summary>
  380. /// Represents an OnCompleted notification to an observer.
  381. /// </summary>
  382. #if !NO_DEBUGGER_ATTRIBUTES
  383. [DebuggerDisplay("OnCompleted()")]
  384. #endif
  385. #if !NO_SERIALIZABLE
  386. [Serializable]
  387. #endif
  388. internal sealed class OnCompletedNotification : Notification<T>
  389. {
  390. /// <summary>
  391. /// Constructs a notification of the end of a sequence.
  392. /// </summary>
  393. public OnCompletedNotification()
  394. {
  395. }
  396. /// <summary>
  397. /// Throws an <see cref="InvalidOperationException"/>.
  398. /// </summary>
  399. public override T Value { get { throw new InvalidOperationException("An OnCompleted notification does not have a value."); } }
  400. /// <summary>
  401. /// Returns <c>null</c>.
  402. /// </summary>
  403. public override Exception Exception => null;
  404. /// <summary>
  405. /// Returns <c>false</c>.
  406. /// </summary>
  407. public override bool HasValue => false;
  408. /// <summary>
  409. /// Returns <see cref="NotificationKind.OnCompleted"/>.
  410. /// </summary>
  411. public override NotificationKind Kind => NotificationKind.OnCompleted;
  412. /// <summary>
  413. /// Returns the hash code for this instance.
  414. /// </summary>
  415. public override int GetHashCode() => typeof(T).GetHashCode() ^ 8510;
  416. /// <summary>
  417. /// Indicates whether this instance and other are equal.
  418. /// </summary>
  419. public override bool Equals(Notification<T> other)
  420. {
  421. if (ReferenceEquals(this, other))
  422. return true;
  423. if (ReferenceEquals(other, null))
  424. return false;
  425. return other.Kind == NotificationKind.OnCompleted;
  426. }
  427. /// <summary>
  428. /// Returns a string representation of this instance.
  429. /// </summary>
  430. public override string ToString() => "OnCompleted()";
  431. /// <summary>
  432. /// Invokes the observer's method corresponding to the notification.
  433. /// </summary>
  434. /// <param name="observer">Observer to invoke the notification on.</param>
  435. public override void Accept(IObserver<T> observer)
  436. {
  437. if (observer == null)
  438. throw new ArgumentNullException(nameof(observer));
  439. observer.OnCompleted();
  440. }
  441. /// <summary>
  442. /// Invokes the observer's method corresponding to the notification.
  443. /// </summary>
  444. /// <param name="observer">Observer to invoke the notification on.</param>
  445. /// <returns>Task indicating the completion of invoking the observer method.</returns>
  446. public override Task AcceptAsync(IAsyncObserver<T> observer)
  447. {
  448. if (observer == null)
  449. throw new ArgumentNullException(nameof(observer));
  450. return observer.OnCompletedAsync();
  451. }
  452. #if NOTYET
  453. /// <summary>
  454. /// Invokes the observer's method corresponding to the notification and returns the produced result.
  455. /// </summary>
  456. /// <param name="observer">Observer to invoke the notification on.</param>
  457. /// <returns>Result produced by the observation.</returns>
  458. public override TResult Accept<TResult>(IObserver<T, TResult> observer)
  459. {
  460. if (observer == null)
  461. throw new ArgumentNullException(nameof(observer));
  462. return observer.OnCompleted();
  463. }
  464. #endif
  465. /// <summary>
  466. /// Invokes the delegate corresponding to the notification.
  467. /// </summary>
  468. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  469. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  470. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  471. public override void Accept(Action<T> onNext, Action<Exception> onError, Action onCompleted)
  472. {
  473. if (onNext == null)
  474. throw new ArgumentNullException(nameof(onNext));
  475. if (onError == null)
  476. throw new ArgumentNullException(nameof(onError));
  477. if (onCompleted == null)
  478. throw new ArgumentNullException(nameof(onCompleted));
  479. onCompleted();
  480. }
  481. /// <summary>
  482. /// Invokes the delegate corresponding to the notification and returns the produced result.
  483. /// </summary>
  484. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  485. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  486. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  487. /// <returns>Result produced by the observation.</returns>
  488. public override TResult Accept<TResult>(Func<T, TResult> onNext, Func<Exception, TResult> onError, Func<TResult> onCompleted)
  489. {
  490. if (onNext == null)
  491. throw new ArgumentNullException(nameof(onNext));
  492. if (onError == null)
  493. throw new ArgumentNullException(nameof(onError));
  494. if (onCompleted == null)
  495. throw new ArgumentNullException(nameof(onCompleted));
  496. return onCompleted();
  497. }
  498. /// <summary>
  499. /// Invokes the delegate corresponding to the notification.
  500. /// </summary>
  501. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  502. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  503. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  504. /// <returns>Task indicating the completion of invoking the delegate.</returns>
  505. public override Task AcceptAsync(Func<T, Task> onNext, Func<Exception, Task> onError, Func<Task> onCompleted)
  506. {
  507. if (onNext == null)
  508. throw new ArgumentNullException(nameof(onNext));
  509. if (onError == null)
  510. throw new ArgumentNullException(nameof(onError));
  511. if (onCompleted == null)
  512. throw new ArgumentNullException(nameof(onCompleted));
  513. return onCompleted();
  514. }
  515. /// <summary>
  516. /// Invokes the delegate corresponding to the notification and returns the produced result.
  517. /// </summary>
  518. /// <typeparam name="TResult">The type of the result returned from the notification handler delegates.</typeparam>
  519. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  520. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  521. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  522. /// <returns>Task containing the result produced by the observation.</returns>
  523. public override Task<TResult> AcceptAsync<TResult>(Func<T, Task<TResult>> onNext, Func<Exception, Task<TResult>> onError, Func<Task<TResult>> onCompleted)
  524. {
  525. if (onNext == null)
  526. throw new ArgumentNullException(nameof(onNext));
  527. if (onError == null)
  528. throw new ArgumentNullException(nameof(onError));
  529. if (onCompleted == null)
  530. throw new ArgumentNullException(nameof(onCompleted));
  531. return onCompleted();
  532. }
  533. }
  534. /// <summary>
  535. /// Determines whether the current <see cref="Notification{T}"/> object has the same observer message payload as a specified <see cref="Notification{T}"/> value.
  536. /// </summary>
  537. /// <param name="other">An object to compare to the current <see cref="Notification{T}"/> object.</param>
  538. /// <returns><c>true</c> if both <see cref="Notification{T}"/> objects have the same observer message payload; otherwise, <c>false</c>.</returns>
  539. /// <remarks>
  540. /// Equality of <see cref="Notification{T}"/> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any).
  541. /// This means two <see cref="Notification{T}"/> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method.
  542. /// In case one wants to determine whether two <see cref="Notification{T}"/> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead.
  543. /// </remarks>
  544. public abstract bool Equals(Notification<T> other);
  545. /// <summary>
  546. /// Determines whether the two specified <see cref="Notification{T}"/> objects have the same observer message payload.
  547. /// </summary>
  548. /// <param name="left">The first <see cref="Notification{T}"/> to compare, or <c>null</c>.</param>
  549. /// <param name="right">The second <see cref="Notification{T}"/> to compare, or <c>null</c>.</param>
  550. /// <returns><c>true</c> if the first <see cref="Notification{T}"/> value has the same observer message payload as the second <see cref="Notification{T}"/> value; otherwise, <c>false</c>.</returns>
  551. /// <remarks>
  552. /// Equality of <see cref="Notification{T}"/> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any).
  553. /// This means two <see cref="Notification{T}"/> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method.
  554. /// In case one wants to determine whether two <see cref="Notification{T}"/> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead.
  555. /// </remarks>
  556. public static bool operator ==(Notification<T> left, Notification<T> right)
  557. {
  558. if (ReferenceEquals(left, right))
  559. return true;
  560. if ((object)left == null || (object)right == null)
  561. return false;
  562. return left.Equals(right);
  563. }
  564. /// <summary>
  565. /// Determines whether the two specified <see cref="Notification{T}"/> objects have a different observer message payload.
  566. /// </summary>
  567. /// <param name="left">The first <see cref="Notification{T}"/> to compare, or <c>null</c>.</param>
  568. /// <param name="right">The second <see cref="Notification{T}"/> to compare, or <c>null</c>.</param>
  569. /// <returns><c>true</c> if the first <see cref="Notification{T}"/> value has a different observer message payload as the second <see cref="Notification{T}"/> value; otherwise, <c>false</c>.</returns>
  570. /// <remarks>
  571. /// Equality of <see cref="Notification{T}"/> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any).
  572. /// This means two <see cref="Notification{T}"/> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method.
  573. /// In case one wants to determine whether two <see cref="Notification{T}"/> objects represent a different observer method call, use Object.ReferenceEquals identity equality instead.
  574. /// </remarks>
  575. public static bool operator !=(Notification<T> left, Notification<T> right) => !(left == right);
  576. /// <summary>
  577. /// Determines whether the specified System.Object is equal to the current <see cref="Notification{T}"/>.
  578. /// </summary>
  579. /// <param name="obj">The System.Object to compare with the current <see cref="Notification{T}"/>.</param>
  580. /// <returns><c>true</c> if the specified System.Object is equal to the current <see cref="Notification{T}"/>; otherwise, <c>false</c>.</returns>
  581. /// <remarks>
  582. /// Equality of <see cref="Notification{T}"/> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any).
  583. /// This means two <see cref="Notification{T}"/> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method.
  584. /// In case one wants to determine whether two <see cref="Notification{T}"/> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead.
  585. /// </remarks>
  586. public override bool Equals(object obj) => Equals(obj as Notification<T>);
  587. /// <summary>
  588. /// Invokes the observer's method corresponding to the notification.
  589. /// </summary>
  590. /// <param name="observer">Observer to invoke the notification on.</param>
  591. public abstract void Accept(IObserver<T> observer);
  592. /// <summary>
  593. /// Invokes the observer's method corresponding to the notification.
  594. /// </summary>
  595. /// <param name="observer">Observer to invoke the notification on.</param>
  596. /// <returns>Task indicating the completion of invoking the observer method.</returns>
  597. public abstract Task AcceptAsync(IAsyncObserver<T> observer);
  598. #if NOTYET
  599. /// <summary>
  600. /// Invokes the observer's method corresponding to the notification and returns the produced result.
  601. /// </summary>
  602. /// <typeparam name="TResult">The type of the result returned from the observer's notification handlers.</typeparam>
  603. /// <param name="observer">Observer to invoke the notification on.</param>
  604. /// <returns>Result produced by the observation.</returns>
  605. public abstract TResult Accept<TResult>(IObserver<T, TResult> observer);
  606. #endif
  607. /// <summary>
  608. /// Invokes the delegate corresponding to the notification.
  609. /// </summary>
  610. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  611. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  612. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  613. public abstract void Accept(Action<T> onNext, Action<Exception> onError, Action onCompleted);
  614. /// <summary>
  615. /// Invokes the delegate corresponding to the notification and returns the produced result.
  616. /// </summary>
  617. /// <typeparam name="TResult">The type of the result returned from the notification handler delegates.</typeparam>
  618. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  619. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  620. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  621. /// <returns>Result produced by the observation.</returns>
  622. public abstract TResult Accept<TResult>(Func<T, TResult> onNext, Func<Exception, TResult> onError, Func<TResult> onCompleted);
  623. /// <summary>
  624. /// Invokes the delegate corresponding to the notification.
  625. /// </summary>
  626. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  627. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  628. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  629. /// <returns>Task indicating the completion of invoking the delegate.</returns>
  630. public abstract Task AcceptAsync(Func<T, Task> onNext, Func<Exception, Task> onError, Func<Task> onCompleted);
  631. /// <summary>
  632. /// Invokes the delegate corresponding to the notification and returns the produced result.
  633. /// </summary>
  634. /// <typeparam name="TResult">The type of the result returned from the notification handler delegates.</typeparam>
  635. /// <param name="onNext">Delegate to invoke for an OnNext notification.</param>
  636. /// <param name="onError">Delegate to invoke for an OnError notification.</param>
  637. /// <param name="onCompleted">Delegate to invoke for an OnCompleted notification.</param>
  638. /// <returns>Task containing the result produced by the observation.</returns>
  639. public abstract Task<TResult> AcceptAsync<TResult>(Func<T, Task<TResult>> onNext, Func<Exception, Task<TResult>> onError, Func<Task<TResult>> onCompleted);
  640. #if NOTYET
  641. /// <summary>
  642. /// Returns an observable sequence with a single notification, using the immediate scheduler.
  643. /// </summary>
  644. /// <returns>The observable sequence that surfaces the behavior of the notification upon subscription.</returns>
  645. public IObservable<T> ToObservable() => ToObservable(ImmediateScheduler.Instance);
  646. /// <summary>
  647. /// Returns an observable sequence with a single notification.
  648. /// </summary>
  649. /// <param name="scheduler">Scheduler to send out the notification calls on.</param>
  650. /// <returns>The observable sequence that surfaces the behavior of the notification upon subscription.</returns>
  651. public IObservable<T> ToObservable(IScheduler scheduler)
  652. {
  653. if (scheduler == null)
  654. throw new ArgumentNullException(nameof(scheduler));
  655. return new AnonymousObservable<T>(observer => scheduler.Schedule(() =>
  656. {
  657. Accept(observer);
  658. if (Kind == NotificationKind.OnNext)
  659. {
  660. observer.OnCompleted();
  661. }
  662. }));
  663. }
  664. #endif
  665. }
  666. /// <summary>
  667. /// Provides a set of static methods for constructing notifications.
  668. /// </summary>
  669. public static class Notification
  670. {
  671. /// <summary>
  672. /// Creates an object that represents an OnNext notification to an observer.
  673. /// </summary>
  674. /// <typeparam name="T">The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence.</typeparam>
  675. /// <param name="value">The value contained in the notification.</param>
  676. /// <returns>The OnNext notification containing the value.</returns>
  677. public static Notification<T> CreateOnNext<T>(T value)
  678. {
  679. return new Notification<T>.OnNextNotification(value);
  680. }
  681. /// <summary>
  682. /// Creates an object that represents an OnError notification to an observer.
  683. /// </summary>
  684. /// <typeparam name="T">The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence.</typeparam>
  685. /// <param name="error">The exception contained in the notification.</param>
  686. /// <returns>The OnError notification containing the exception.</returns>
  687. /// <exception cref="ArgumentNullException"><paramref name="error"/> is null.</exception>
  688. public static Notification<T> CreateOnError<T>(Exception error)
  689. {
  690. if (error == null)
  691. throw new ArgumentNullException(nameof(error));
  692. return new Notification<T>.OnErrorNotification(error);
  693. }
  694. /// <summary>
  695. /// Creates an object that represents an OnCompleted notification to an observer.
  696. /// </summary>
  697. /// <typeparam name="T">The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence.</typeparam>
  698. /// <returns>The OnCompleted notification.</returns>
  699. public static Notification<T> CreateOnCompleted<T>()
  700. {
  701. return new Notification<T>.OnCompletedNotification();
  702. }
  703. }
  704. }
  705. #pragma warning restore 0659
  706. #pragma warning restore 0661