public static class LinqHelper{public static IEnumerable<T> Select<T>(params T[] args) => args;public static IEnumerable<T> SelectMany<T>(params IEnumerable<T>[] args) => args.SelectMany(x => x);public static List<T> List<T>(params T[] args) => args.ToList();public static IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> src, int size) => src.Where((x, i) => i % size == 0).Select((x, i) => src.Skip(i * size).Take(size));public static bool HasSharedItem<T>(IEnumerable<T> left, IEnumerable<T> right) => left.Any(l => right.Any(r => l != null && r != null && l.Equals(r)));public static T GetValueIfExactOne<T>(IEnumerable<T> values, T defValue = default){var distinct = values.Distinct();return distinct.Count() == 1 ? distinct.First() : defValue;}public static async Task<IEnumerable<T>> FromAsync<T>(IAsyncEnumerable<T> items){var list = new List<T>();await foreach (var item in items) { list.Add(item); }return list;}public static async Task<IEnumerable<U>> FromAsync<T, U>(IAsyncEnumerable<T> items, Func<T, U> converter){var list = new List<U>();await foreach (var item in items) { list.Add(converter(item)); }return list;}public static T MinOrDefault<T>(this IEnumerable<T> sequence, T defValue = default(T)) => sequence.Any() ? sequence.Min() : defValue;public static T MaxOrDefault<T>(this IEnumerable<T> sequence, T defValue = default(T)) => sequence.Any() ? sequence.Max() : defValue;public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self) => self.Select((item, index) => (item, index));// filter where conditions in (Entity Framework) queries based on condition e.g:// AsQueryable().WhereIf(onlyActiveItems, x => x.Active).ToListAsync();public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, bool condition, Func<TSource, bool> predicate) where TSource : class{return condition ? source.Where(predicate) : source;}public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate) where TSource : class{return condition ? source.Where(predicate) : source;}public static IQueryable<TSource> IncludeIf<TSource, TProperty>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, TProperty>> propertySelector) where TSource : class{return condition ? source.Include(propertySelector) : source;}public static IQueryable<TSource> SkipIf<TSource>(this IQueryable<TSource> source, bool condition, int quantityToSkip) where TSource : class{return condition ? source.Skip(quantityToSkip) : source;}public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> recursiveSelector){foreach (var i in source){yield return i;var directChildren = recursiveSelector(i);var allChildren = SelectRecursive(directChildren, recursiveSelector);foreach (var c in allChildren){yield return c;}}}public static IQueryable<TSource> TakeIf<TSource>(this IQueryable<TSource> source, bool condition, int quantityToTake) where TSource : class{return condition ? source.Take(quantityToTake) : source;}public static Dictionary<Y, T> ToDictionarySafe<T, Y>(this IEnumerable<T> items, Func<T, Y> keySelector) => items.GroupBy(x => keySelector(x)).Where(x => x.Key != null).Select(x => x.First()).ToDictionary(x => keySelector(x));// Comparable with: .GroupBy(x => x.Property).Select(x => x.First())// but possibly faster and with yield return// update: function exists in dotnet 6public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector){var seenKeys = new HashSet<TKey>();foreach (TSource element in source)if (seenKeys.Add(keySelector(element)))yield return element;}public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable){var knownKeys = new HashSet<T>();return enumerable.Any(item => !knownKeys.Add(item));}public static bool None<T>(this IEnumerable<T> list) => !list.Any();public static IEnumerable<int> GetRange(int min, int max){for (var i = min; i <= max; i++)yield return i;}public static List<List<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> list){return list.SelectMany(inner => inner.Select((item, index) => new { item, index })).GroupBy(i => i.index, i => i.item).Select(g => g.ToList()).ToList();}public static (List<T> TrueItems, List<T> FalseItems) Partition<T>(this IEnumerable<T> source, Func<T, bool> predicate){var trueItems = new List<T>();var falseItems = new List<T>();foreach (var item in source){if (predicate(item))trueItems.Add(item);elsefalseItems.Add(item);}return (trueItems, falseItems);}}
WhereIf example
// Original: query with separate if statementspublic async Task<IEnumerable<PurchaseContractExpectedAndDelivered>> GetExpectedAndDeliveredQuantitiesForContract(PurchaseQuantityFilter filter){using var unitOfWork = GetUnitOfWork();var query = Query<DmPurchaseContractLine>(unitOfWork);if (filter.PurchaseContractId != null)query = query.Where(x => x.PurchaseContractId == filter.PurchaseContractId)if (filter.PurchaseContractLineId != null)query = query.Where(x => x.Id == filter.PurchaseContractLineId);var selectQuery = query.Select(x => new PurchaseContractExpectedAndDelivered{PurchaseContractId = x.PurchaseContractId,PurchaseContractLineId = x.Id,ExpectedKg = x.WeightKg,DeliveredKg = x.PurchaseShipments.Sum(x => x.WeightKg),DeliveredBoxes = x.PurchaseShipments.Sum(x => x.Boxes),});return await selectQuery.ToListAsync();}// With an WhereIf: query as single statementpublic async Task<IEnumerable<PurchaseContractExpectedAndDelivered>> GetExpectedAndDeliveredQuantitiesForContract(PurchaseQuantityFilter filter){using var unitOfWork = GetUnitOfWork();var query = Query<DmPurchaseContractLine>(unitOfWork).WhereIf(filter.PurchaseContractId != null, x => x.PurchaseContractId == filter.PurchaseContractId).WhereIf(filter.PurchaseContractLineId != null, x => x.Id == filter.PurchaseContractLineId);.Select(x => new PurchaseContractExpectedAndDelivered{PurchaseContractId = x.PurchaseContractId,PurchaseContractLineId = x.Id,ExpectedKg = x.WeightKg,DeliveredKg = x.PurchaseShipments.Sum(x => x.WeightKg),DeliveredBoxes = x.PurchaseShipments.Sum(x => x.Boxes),});return await query.ToListAsync();}
See also:
- https://solidt.eu/site/c-iasyncenumerable/
- https://solidt.eu/site/c-async-selectforeach-with-yield-return/
521600cookie-checkC# LinqHelper