Do.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. namespace System.Linq
  6. {
  7. public static partial class EnumerableEx
  8. {
  9. /// <summary>
  10. /// Lazily invokes an action for each value in the sequence.
  11. /// </summary>
  12. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  13. /// <param name="source">Source sequence.</param>
  14. /// <param name="onNext">Action to invoke for each element.</param>
  15. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  16. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
  17. {
  18. if (source == null)
  19. {
  20. throw new ArgumentNullException(nameof(source));
  21. }
  22. if (onNext == null)
  23. {
  24. throw new ArgumentNullException(nameof(onNext));
  25. }
  26. return DoHelper(source, onNext, _ => { }, () => { });
  27. }
  28. /// <summary>
  29. /// Lazily invokes an action for each value in the sequence, and executes an action for successful termination.
  30. /// </summary>
  31. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  32. /// <param name="source">Source sequence.</param>
  33. /// <param name="onNext">Action to invoke for each element.</param>
  34. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  35. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  36. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
  37. {
  38. if (source == null)
  39. {
  40. throw new ArgumentNullException(nameof(source));
  41. }
  42. if (onNext == null)
  43. {
  44. throw new ArgumentNullException(nameof(onNext));
  45. }
  46. if (onCompleted == null)
  47. {
  48. throw new ArgumentNullException(nameof(onCompleted));
  49. }
  50. return DoHelper(source, onNext, _ => { }, onCompleted);
  51. }
  52. /// <summary>
  53. /// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination.
  54. /// </summary>
  55. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  56. /// <param name="source">Source sequence.</param>
  57. /// <param name="onNext">Action to invoke for each element.</param>
  58. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  59. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  60. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
  61. {
  62. if (source == null)
  63. {
  64. throw new ArgumentNullException(nameof(source));
  65. }
  66. if (onNext == null)
  67. {
  68. throw new ArgumentNullException(nameof(onNext));
  69. }
  70. if (onError == null)
  71. {
  72. throw new ArgumentNullException(nameof(onError));
  73. }
  74. return DoHelper(source, onNext, onError, () => { });
  75. }
  76. /// <summary>
  77. /// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional
  78. /// termination.
  79. /// </summary>
  80. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  81. /// <param name="source">Source sequence.</param>
  82. /// <param name="onNext">Action to invoke for each element.</param>
  83. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  84. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  85. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  86. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
  87. {
  88. if (source == null)
  89. {
  90. throw new ArgumentNullException(nameof(source));
  91. }
  92. if (onNext == null)
  93. {
  94. throw new ArgumentNullException(nameof(onNext));
  95. }
  96. if (onError == null)
  97. {
  98. throw new ArgumentNullException(nameof(onError));
  99. }
  100. if (onCompleted == null)
  101. {
  102. throw new ArgumentNullException(nameof(onCompleted));
  103. }
  104. return DoHelper(source, onNext, onError, onCompleted);
  105. }
  106. /// <summary>
  107. /// Lazily invokes observer methods for each value in the sequence, and upon successful or exceptional termination.
  108. /// </summary>
  109. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  110. /// <param name="source">Source sequence.</param>
  111. /// <param name="observer">Observer to invoke notification calls on.</param>
  112. /// <returns>Sequence exhibiting the side-effects of observer method invocation upon enumeration.</returns>
  113. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, IObserver<TSource> observer)
  114. {
  115. if (source == null)
  116. {
  117. throw new ArgumentNullException(nameof(source));
  118. }
  119. if (observer == null)
  120. {
  121. throw new ArgumentNullException(nameof(observer));
  122. }
  123. return DoHelper(source, observer.OnNext, observer.OnError, observer.OnCompleted);
  124. }
  125. /// <summary>
  126. /// Generates an enumerable sequence by repeating a source sequence as long as the given loop postcondition holds.
  127. /// </summary>
  128. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  129. /// <param name="source">Source sequence to repeat while the condition evaluates true.</param>
  130. /// <param name="condition">Loop condition.</param>
  131. /// <returns>Sequence generated by repeating the given sequence until the condition evaluates to false.</returns>
  132. public static IEnumerable<TResult> DoWhile<TResult>(this IEnumerable<TResult> source, Func<bool> condition)
  133. {
  134. if (source == null)
  135. {
  136. throw new ArgumentNullException(nameof(source));
  137. }
  138. if (condition == null)
  139. {
  140. throw new ArgumentNullException(nameof(condition));
  141. }
  142. return source.Concat(While(condition, source));
  143. }
  144. private static IEnumerable<TSource> DoHelper<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
  145. {
  146. using (var e = source.GetEnumerator())
  147. {
  148. while (true)
  149. {
  150. var current = default(TSource);
  151. try
  152. {
  153. if (!e.MoveNext())
  154. {
  155. break;
  156. }
  157. current = e.Current;
  158. }
  159. catch (Exception ex)
  160. {
  161. onError(ex);
  162. throw;
  163. }
  164. onNext(current);
  165. yield return current;
  166. }
  167. onCompleted();
  168. }
  169. }
  170. }
  171. }