PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Fluent/EnumerableExtensions.cs

#
C# | 178 lines | 80 code | 17 blank | 81 comment | 11 complexity | 2063a96df3d7986e8baa2174a55b5dfa MD5 | raw file
  1. // <copyright file="EnumerableExtensions.cs" company="Fluent.NET">
  2. // Microsoft Public License (Ms-PL)
  3. // </copyright>
  4. // <author>Chris Eargle</author>
  5. // <email>kodefuguru@live.com</email>
  6. // <date>2009-12-15</date>
  7. // <summary>Contains a fluent interface for IEnumerable&lt;T&gt;</summary>
  8. namespace Fluent
  9. {
  10. using System;
  11. using System.Collections.Generic;
  12. using System.ComponentModel;
  13. using System.Diagnostics.CodeAnalysis;
  14. using System.Diagnostics.Contracts;
  15. using System.Linq;
  16. /// <summary>
  17. /// Extensions for <see cref="IEnumerable&lt;T&gt;"/>
  18. /// </summary>
  19. [Browsable(false)]
  20. [EditorBrowsable(EditorBrowsableState.Never)]
  21. public static class EnumerableExtensions
  22. {
  23. /// <summary>
  24. /// Delimits the strings with the default delimited, a comma.
  25. /// </summary>
  26. /// <typeparam name="T">The type of the elements of source.</typeparam>
  27. /// <param name="source">The sequence with which to create a delimited string.</param>
  28. /// <returns>
  29. /// A comma-separated value <see cref="System.String"/>
  30. /// </returns>
  31. public static string Delimit<T>(this IEnumerable<T> source)
  32. {
  33. Contract.Requires(source != null);
  34. return source.Select(t => t.ToString()).Delimit();
  35. }
  36. /// <summary>
  37. /// Creates a delimited string from a sequence.
  38. /// </summary>
  39. /// <typeparam name="T">The type of the elements of source.</typeparam>
  40. /// <param name="source">The sequence with which to create a delimited string.</param>
  41. /// <param name="delimiter">The delimiter with which to separate the strings.</param>
  42. /// <returns>A <see cref="System.String"/> consisting of the elements of value interspersed with the separator string.</returns>
  43. public static string Delimit<T>(this IEnumerable<T> source, string delimiter)
  44. {
  45. Contract.Requires(source != null);
  46. return source.Select(t => t.ToString()).Delimit(delimiter);
  47. }
  48. /// <summary>
  49. /// Determines whether a sequence is empty.
  50. /// </summary>
  51. /// <typeparam name="T">The type of the elements of source.</typeparam>
  52. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/>to check for emptiness.</param>
  53. /// <returns>
  54. /// true if the source sequence is empty; otherwise, false.
  55. /// </returns>
  56. /// <remarks><para>This provides better readability than !source.Any().</para>
  57. /// <para>There already exists an Enumerable.Empty&lt;T&gt;, which is probably why it wasn't
  58. /// included in the .NET Framework. This method exists in a class called EnumerableExtensions,
  59. /// so there should not be any conflict.</para></remarks>
  60. public static bool Empty<T>(this IEnumerable<T> source)
  61. {
  62. Contract.Requires(source != null);
  63. return !source.Any();
  64. }
  65. /// <summary>
  66. /// Immediately executes an action on each element in a sequence.
  67. /// </summary>
  68. /// <typeparam name="T">The type of the elements of source.</typeparam>
  69. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> which contains elements to be acted upon.</param>
  70. /// <param name="action">The action to perform on elements in source.</param>
  71. /// <remarks><para>Execute is preferable name to ForEach as it states what is actually happening.
  72. /// The action is being invoked on each element in the enumerable immediately, without
  73. /// returning anything.</para><para>ForEach is ambiguous in its name. Does it return anything?
  74. /// Does it execute immediately or is it deferred?</para></remarks>
  75. public static void Execute<T>(this IEnumerable<T> source, Action<T> action)
  76. {
  77. Contract.Requires(source != null);
  78. Contract.Requires(action != null);
  79. foreach (T element in source)
  80. {
  81. action(element);
  82. }
  83. }
  84. /// <summary>
  85. /// Iterates over a sequence and executes an action.
  86. /// </summary>
  87. /// <typeparam name="T">The type of the elements of source.</typeparam>
  88. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> which contains elements to iterated.</param>
  89. /// <param name="action">The action to perform on elements in source.</param>
  90. /// <returns>The original sequence.</returns>
  91. /// <remarks>Iterate provides deferred execution of an action over a sequence and returns the original
  92. /// sequence. This method and Execute are the two primary versions of ForEach others have implemented.</remarks>
  93. [Obsolete("Use Each instead")]
  94. public static IEnumerable<T> Iterate<T>(this IEnumerable<T> source, Action<T> action)
  95. {
  96. Contract.Requires(source != null);
  97. Contract.Requires(action != null);
  98. foreach (T element in source)
  99. {
  100. action(element);
  101. yield return element;
  102. }
  103. }
  104. /// <summary>
  105. /// Iterates over a sequence and executes an action.
  106. /// </summary>
  107. /// <typeparam name="T">The type of the elements of source.</typeparam>
  108. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> which contains elements to iterated.</param>
  109. /// <param name="action">The action to perform on elements in source.</param>
  110. /// <returns>The original sequence.</returns>
  111. /// <remarks><para>Each provides deferred execution of an action over a sequence and returns the original
  112. /// sequence. This method and Execute are the two primary versions of ForEach others have implemented.</para>
  113. /// <para>Each was chosen over Iterate due to shorter syntax and the name being used in jQuery.</para></remarks>
  114. public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Action<T> action)
  115. {
  116. Contract.Requires(source != null);
  117. Contract.Requires(action != null);
  118. foreach (T element in source)
  119. {
  120. action(element);
  121. yield return element;
  122. }
  123. }
  124. /// <summary>
  125. /// Partitions the specified source.
  126. /// </summary>
  127. /// <typeparam name="T">The type of the elements of source.</typeparam>
  128. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> to be partitioned.</param>
  129. /// <param name="size">The maximum size of each partition.</param>
  130. /// <returns>Multiple <see cref="IEnumerable&lt;T&gt;"/> partitioned by the size parameter.</returns>
  131. /// <remarks>See http://www.kodefuguru.com/post/2009/12/20/Refactoring-Partition-List.aspx</remarks>
  132. [SuppressMessage("Microsoft.Design", "CA1006", Justification = "Nested generics is justified for partitioning sequences.")]
  133. public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int size)
  134. {
  135. Contract.Requires(source != null);
  136. Contract.Requires(size > 0);
  137. int index = 1;
  138. IEnumerable<T> partition = source.Take(size).AsEnumerable();
  139. while (partition.Any())
  140. {
  141. yield return partition;
  142. partition = source.Skip(index++ * size).Take(size).AsEnumerable();
  143. }
  144. }
  145. /// <summary>
  146. /// Fluent Interface for adding an item to a sequence.
  147. /// </summary>
  148. /// <typeparam name="T">The type of the elements of source.</typeparam>
  149. /// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> to have an item added to it.</param>
  150. /// <param name="item">The item to be added.</param>
  151. /// <returns>An <see cref="IEnumerable&lt;T&gt;"/> with the item.</returns>
  152. public static IEnumerable<T> With<T>(this IEnumerable<T> source, T item)
  153. {
  154. foreach (T t in source)
  155. {
  156. yield return t;
  157. }
  158. yield return item;
  159. }
  160. }
  161. }