ObservableEx.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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.Reactive.Concurrency;
  6. namespace System.Reactive.Linq
  7. {
  8. /// <summary>
  9. /// Provides a set of static methods for writing in-memory queries over observable sequences.
  10. /// </summary>
  11. public static class ObservableEx
  12. {
  13. private static IQueryLanguageEx s_impl = QueryServices.GetQueryImpl<IQueryLanguageEx>(new QueryLanguageEx());
  14. #region Create
  15. /// <summary>
  16. /// Subscribes to each observable sequence returned by the iteratorMethod in sequence and returns the observable sequence of values sent to the observer given to the iteratorMethod.
  17. /// </summary>
  18. /// <typeparam name="TResult">The type of the elements in the produced sequence.</typeparam>
  19. /// <param name="iteratorMethod">Iterator method that produces elements in the resulting sequence by calling the given observer.</param>
  20. /// <returns>An observable sequence obtained by running the iterator and returning the elements that were sent to the observer.</returns>
  21. /// <exception cref="ArgumentNullException"><paramref name="iteratorMethod"/> is null.</exception>
  22. [Experimental]
  23. public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, IEnumerable<IObservable<object>>> iteratorMethod)
  24. {
  25. if (iteratorMethod == null)
  26. throw new ArgumentNullException("iteratorMethod");
  27. return s_impl.Create<TResult>(iteratorMethod);
  28. }
  29. /// <summary>
  30. /// Subscribes to each observable sequence returned by the iteratorMethod in sequence and produces a Unit value on the resulting sequence for each step of the iteration.
  31. /// </summary>
  32. /// <param name="iteratorMethod">Iterator method that drives the resulting observable sequence.</param>
  33. /// <returns>An observable sequence obtained by running the iterator and returning Unit values for each iteration step.</returns>
  34. /// <exception cref="ArgumentNullException"><paramref name="iteratorMethod"/> is null.</exception>
  35. [Experimental]
  36. public static IObservable<Unit> Create(Func<IEnumerable<IObservable<object>>> iteratorMethod)
  37. {
  38. if (iteratorMethod == null)
  39. throw new ArgumentNullException("iteratorMethod");
  40. return s_impl.Create(iteratorMethod);
  41. }
  42. #endregion
  43. #region Expand
  44. /// <summary>
  45. /// Expands an observable sequence by recursively invoking selector, using the specified scheduler to enumerate the queue of obtained sequences.
  46. /// </summary>
  47. /// <typeparam name="TSource">The type of the elements in the source sequence and each of the recursively expanded sources obtained by running the selector function.</typeparam>
  48. /// <param name="source">Source sequence with the initial elements.</param>
  49. /// <param name="selector">Selector function to invoke for each produced element, resulting in another sequence to which the selector will be invoked recursively again.</param>
  50. /// <param name="scheduler">Scheduler on which to perform the expansion by enumerating the internal queue of obtained sequences.</param>
  51. /// <returns>An observable sequence containing all the elements produced by the recursive expansion.</returns>
  52. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> or <paramref name="scheduler"/> is null.</exception>
  53. [Experimental]
  54. public static IObservable<TSource> Expand<TSource>(this IObservable<TSource> source, Func<TSource, IObservable<TSource>> selector, IScheduler scheduler)
  55. {
  56. if (source == null)
  57. throw new ArgumentNullException("source");
  58. if (selector == null)
  59. throw new ArgumentNullException("selector");
  60. if (scheduler == null)
  61. throw new ArgumentNullException("scheduler");
  62. return s_impl.Expand<TSource>(source, selector, scheduler);
  63. }
  64. /// <summary>
  65. /// Expands an observable sequence by recursively invoking selector.
  66. /// </summary>
  67. /// <typeparam name="TSource">The type of the elements in the source sequence and each of the recursively expanded sources obtained by running the selector function.</typeparam>
  68. /// <param name="source">Source sequence with the initial elements.</param>
  69. /// <param name="selector">Selector function to invoke for each produced element, resulting in another sequence to which the selector will be invoked recursively again.</param>
  70. /// <returns>An observable sequence containing all the elements produced by the recursive expansion.</returns>
  71. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  72. [Experimental]
  73. public static IObservable<TSource> Expand<TSource>(this IObservable<TSource> source, Func<TSource, IObservable<TSource>> selector)
  74. {
  75. if (source == null)
  76. throw new ArgumentNullException("source");
  77. if (selector == null)
  78. throw new ArgumentNullException("selector");
  79. return s_impl.Expand<TSource>(source, selector);
  80. }
  81. #endregion
  82. #region ForkJoin
  83. /// <summary>
  84. /// Runs two observable sequences in parallel and combines their last elemenets.
  85. /// </summary>
  86. /// <typeparam name="TSource1">The type of the elements in the first source sequence.</typeparam>
  87. /// <typeparam name="TSource2">The type of the elements in the second source sequence.</typeparam>
  88. /// <typeparam name="TResult">The type of the elements in the result sequence, returned by the selector function.</typeparam>
  89. /// <param name="first">First observable sequence.</param>
  90. /// <param name="second">Second observable sequence.</param>
  91. /// <param name="resultSelector">Result selector function to invoke with the last elements of both sequences.</param>
  92. /// <returns>An observable sequence with the result of calling the selector function with the last elements of both input sequences.</returns>
  93. /// <exception cref="ArgumentNullException"><paramref name="first"/> or <paramref name="second"/> or <paramref name="resultSelector"/> is null.</exception>
  94. [Experimental]
  95. public static IObservable<TResult> ForkJoin<TSource1, TSource2, TResult>(this IObservable<TSource1> first, IObservable<TSource2> second, Func<TSource1, TSource2, TResult> resultSelector)
  96. {
  97. if (first == null)
  98. throw new ArgumentNullException("first");
  99. if (second == null)
  100. throw new ArgumentNullException("second");
  101. if (resultSelector == null)
  102. throw new ArgumentNullException("resultSelector");
  103. return s_impl.ForkJoin<TSource1, TSource2, TResult>(first, second, resultSelector);
  104. }
  105. /// <summary>
  106. /// Runs all specified observable sequences in parallel and collects their last elements.
  107. /// </summary>
  108. /// <typeparam name="TSource">The type of the elements in the source sequences.</typeparam>
  109. /// <param name="sources">Observable sequence to collect the last elements for.</param>
  110. /// <returns>An observable sequence with an array collecting the last elements of all the input sequences.</returns>
  111. /// <exception cref="ArgumentNullException"><paramref name="sources"/> is null.</exception>
  112. [Experimental]
  113. public static IObservable<TSource[]> ForkJoin<TSource>(params IObservable<TSource>[] sources)
  114. {
  115. if (sources == null)
  116. throw new ArgumentNullException("sources");
  117. return s_impl.ForkJoin<TSource>(sources);
  118. }
  119. /// <summary>
  120. /// Runs all observable sequences in the enumerable sources sequence in parallel and collect their last elements.
  121. /// </summary>
  122. /// <typeparam name="TSource">The type of the elements in the source sequences.</typeparam>
  123. /// <param name="sources">Observable sequence to collect the last elements for.</param>
  124. /// <returns>An observable sequence with an array collecting the last elements of all the input sequences.</returns>
  125. /// <exception cref="ArgumentNullException"><paramref name="sources"/> is null.</exception>
  126. [Experimental]
  127. public static IObservable<TSource[]> ForkJoin<TSource>(this IEnumerable<IObservable<TSource>> sources)
  128. {
  129. if (sources == null)
  130. throw new ArgumentNullException("sources");
  131. return s_impl.ForkJoin<TSource>(sources);
  132. }
  133. #endregion
  134. #region Let
  135. /// <summary>
  136. /// Returns an observable sequence that is the result of invoking the selector on the source sequence, without sharing subscriptions.
  137. /// This operator allows for a fluent style of writing queries that use the same sequence multiple times.
  138. /// </summary>
  139. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  140. /// <typeparam name="TResult">The type of the elements in the result sequence.</typeparam>
  141. /// <param name="source">Source sequence that will be shared in the selector function.</param>
  142. /// <param name="selector">Selector function which can use the source sequence as many times as needed, without sharing subscriptions to the source sequence.</param>
  143. /// <returns>An observable sequence that contains the elements of a sequence produced by multicasting the source sequence within a selector function.</returns>
  144. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
  145. [Experimental]
  146. public static IObservable<TResult> Let<TSource, TResult>(this IObservable<TSource> source, Func<IObservable<TSource>, IObservable<TResult>> selector)
  147. {
  148. if (source == null)
  149. throw new ArgumentNullException("source");
  150. if (selector == null)
  151. throw new ArgumentNullException("selector");
  152. return s_impl.Let<TSource, TResult>(source, selector);
  153. }
  154. #endregion
  155. #region ManySelect
  156. /// <summary>
  157. /// Comonadic bind operator.
  158. /// </summary>
  159. [Experimental]
  160. public static IObservable<TResult> ManySelect<TSource, TResult>(this IObservable<TSource> source, Func<IObservable<TSource>, TResult> selector, IScheduler scheduler)
  161. {
  162. if (source == null)
  163. throw new ArgumentNullException("source");
  164. if (selector == null)
  165. throw new ArgumentNullException("selector");
  166. if (scheduler == null)
  167. throw new ArgumentNullException("scheduler");
  168. return s_impl.ManySelect<TSource, TResult>(source, selector, scheduler);
  169. }
  170. /// <summary>
  171. /// Comonadic bind operator.
  172. /// </summary>
  173. [Experimental]
  174. public static IObservable<TResult> ManySelect<TSource, TResult>(this IObservable<TSource> source, Func<IObservable<TSource>, TResult> selector)
  175. {
  176. if (source == null)
  177. throw new ArgumentNullException("source");
  178. if (selector == null)
  179. throw new ArgumentNullException("selector");
  180. return s_impl.ManySelect<TSource, TResult>(source, selector);
  181. }
  182. #endregion
  183. #region ToListObservable
  184. /// <summary>
  185. /// Immediately subscribes to source and retains the elements in the observable sequence.
  186. /// </summary>
  187. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  188. /// <param name="source">Source sequence.</param>
  189. /// <returns>Object that's both an observable sequence and a list which can be used to access the source sequence's elements.</returns>
  190. /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
  191. [Experimental]
  192. public static ListObservable<TSource> ToListObservable<TSource>(this IObservable<TSource> source)
  193. {
  194. if (source == null)
  195. throw new ArgumentNullException("source");
  196. return s_impl.ToListObservable<TSource>(source);
  197. }
  198. #endregion
  199. }
  200. }