using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AggregateConfigBuildTask { /// /// Contains extension methods for , providing additional /// functionality available in future .NET versions. /// public static class ListExtensions { /// /// Splits a list into chunks of the specified size. /// /// The list to split into chunks. /// The size of each chunk. /// An IEnumerable of string arrays, each containing a chunk of the original list. /// When chunk size is 0 or less /// is null. public static IEnumerable> Chunk(this ICollection source, int chunkSize) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (chunkSize <= 0) { throw new ArgumentOutOfRangeException(nameof(chunkSize), "Chunk size must be greater than 0."); } return FetchChunks(); IEnumerable> FetchChunks() { var list = source as List ?? source.ToList(); for (int i = 0; i < list.Count; i += chunkSize) { yield return list.GetRange(i, Math.Min(chunkSize, list.Count - i)); } } } /// /// Asynchronously processes each element of a collection in parallel, with a limit on the number of concurrent tasks. /// /// The type of elements in the source collection. /// The collection of elements to process. /// The maximum number of tasks to run concurrently. /// The asynchronous delegate to execute for each element in the source collection. /// A task that represents the asynchronous processing of the collection. /// Thrown if the source or body is null. /// Thrown if the degree of parallelism is less than 1. public static async Task ForEachAsync( this IEnumerable source, int degreeOfParallelism, Func body) { if (source == null) throw new ArgumentNullException(nameof(source)); if (body == null) throw new ArgumentNullException(nameof(body)); if (degreeOfParallelism < 1) throw new ArgumentOutOfRangeException(nameof(degreeOfParallelism), "Degree of parallelism must be at least 1."); using (var semaphore = new SemaphoreSlim(degreeOfParallelism)) { var tasks = source.Select(async item => { await semaphore.WaitAsync().ConfigureAwait(false); try { await body(item).ConfigureAwait(false); } finally { semaphore.Release(); } }); await Task.WhenAll(tasks).ConfigureAwait(false); } } } }