You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document provides a reference for all extension methods available across the DataLinq extension libraries, organized by functionality and target type.
Library Overview
Library
Target Type
Paradigm
Namespace
DataLinq.Extensions.EnumerableExtensions
IEnumerable<T>
Synchronous Sequential
DataLinq
DataLinq.Extensions.AsyncEnumerableExtensions
IAsyncEnumerable<T>
Asynchronous Sequential
DataLinq
DataLinq.Extensions.ParallelQueryExtensions
ParallelQuery<T>
Synchronous Parallel (PLINQ)
DataLinq.Parallel
DataLinq.Extensions.ParallelAsyncQueryExtensions
ParallelAsyncQuery<T>
Asynchronous Parallel
DataLinq.Parallel
1. Cases Pattern
The categorization pattern for conditional branching in streaming pipelines.
Cases Methods
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
Cases<C,T>((C,T) items, categories[])
✅
✅
✅
✅
Cases<T>(predicates[])
✅
✅
✅
✅
SelectCase Methods
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
SelectCase<T,R>(Func<T,R>[])
✅
✅
✅
✅
SelectCase<T,R>(Func<T,int,R>[])
✅
✅
✅
✅
SelectCase<T,R,Y>(Func<R,Y>[])
✅
✅
✅
✅
SelectCase<T,R,Y>(Func<R,int,Y>[])
✅
✅
✅
✅
ForEachCase Methods
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
ForEachCase(Action[])
✅
✅
✅
✅
ForEachCase(Action<T>[])
✅
✅
✅
✅
ForEachCase(Action<T,int>[])
✅
✅
✅
✅
ForEachCase<T,R>(Action[])
✅
✅
✅
✅
ForEachCase<T,R>(Action<R>[])
✅
✅
✅
✅
ForEachCase<T,R>(Action<R,int>[])
✅
✅
✅
✅
UnCase / AllCases Methods
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
UnCase<T>
✅
✅
✅
✅
UnCase<T,Y>
✅
✅
✅
✅
AllCases<T,R>
✅
✅
✅
✅
2. Core Extensions
Merging & Slicing
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
Notes
MergeOrdered<T>(other, comparer)
✅
✅
❌
❌
Comparer Func<T,T,bool> is required
Take(start, count)
✅
✅
✅
❌
Convenience wrapper for Skip+Take
Conditional Termination
Inclusive semantics: All Until overloads are inclusive — the element that satisfies the stop condition is yielded before enumeration stops. For Until(int lastIdx), the element at lastIdx is included in the output.
⚠️ Known Issue:Sum(float) and Sum(decimal) on ParallelQuery conflict with System.Linq.ParallelEnumerable.Sum, causing ambiguous call errors. Workaround: Call explicitly via DataLinq.Parallel.ParallelQueryExtensions.Sum(query).
3. Debugging Extensions
Method
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
Spy(tag)
✅
✅
✅
✅
Spy<T>(tag, customFormatter)
✅
✅
✅
✅
Note: Spy(tag) is a convenience overload for IEnumerable<string> / IAsyncEnumerable<string> that uses ToString() automatically. For non-string streams, use Spy<T>(tag, item => item.ToString()) where you provide the display logic via Func<T, string>.
DataLinq.NET includes lightweight reimplementations of common System.Linq.Async operators in AsyncLinqOperators.cs to reduce external dependencies.
Query Operators
Method
Overloads
Description
Select<T,R>
2
Project elements (with/without index)
SelectMany<T,R>
4
Flatten nested sequences
Where<T>
3
Filter elements
Distinct<T>
1
Remove duplicates
Concat<T>
1
Concatenate two sequences
Append<T>
1
Add element at end
Prepend<T>
1
Add element at beginning
Slicing Operators
Method
Overloads
Description
Take<T>
5
Take count, range, slice, or while predicate is true
Skip<T>
2
Skip count or while predicate is true
SkipWhile<T>
2
Skip while predicate is true
Terminal Operators
Method
Overloads
Description
First<T>
3
First element (throws if empty)
FirstOrDefault<T>
3
First element or default
Any<T>
3
Check if any element exists
Aggregate<T>
2
Reduce sequence to single value
Materialization Operators
Method
Description
ToList<T>
Materialize to List<T>
ToArray<T>
Materialize to T[]
ToDictionary<T,K,V>
Materialize to Dictionary<K,V>
Batching
Method
Description
Buffer<T>(size)
Split into fixed-size batches
8. Polling and Ingestion Extensions
These extension methods are defined on delegates (Func<T> and TryPollAction<T>) to facilitate periodic data acquisition (e.g., REST API polling) into a unified IAsyncEnumerable<T> stream.
Polling API Reference
Method
Signature
Description
Poll<T>(interval, token)
this Func<T> pollAction, TimeSpan interval
Infinite periodic polling of a synchronous delegate.
Poll<T>(interval, condition, token)
this Func<T> pollAction, TimeSpan interval, Func<T, bool> stopCondition
Periodic polling that stops when stopCondition is satisfied.
Poll<T>(interval, token)
this TryPollAction<T> tryPollAction, TimeSpan interval
Polls a TryPollAction<T> delegate; terminates the stream when it returns false.
Poll<T>(interval, condition, token)
this TryPollAction<T> tryPollAction, TimeSpan interval, Func<T, bool> stopCondition
Polls a TryPollAction<T> delegate; terminates when stopCondition or false is returned.
Note: All overloads support passing a CancellationToken for cooperative interruption.
Summary Matrix
Category
IEnumerable
IAsyncEnumerable
ParallelQuery
ParallelAsyncQuery
Cases Pattern
✅ Full
✅ Full
✅ Full
✅ Full
Core Extensions
✅ Full
✅ Full
⚠️ Partial
⚠️ Partial
Debugging
✅ Full
✅ Full
⚠️ Partial
⚠️ Partial
Flattening
✅ 2 methods
✅ 6 methods
❌
❌
Enumerator
✅ 2 methods
✅ 2 methods
❌
❌
Aggregation
❌
❌
✅ 4 methods
✅ 2 methods
Usage Notes
Thread Safety
All parallel extension delegates may execute concurrently
Captured state must be thread-safe
Console output in Spy is serialized via internal locks
Lazy Execution
Methods returning IEnumerable<T>, IAsyncEnumerable<T>, ParallelQuery<T>, or ParallelAsyncQuery<T> are lazy
Methods returning void or Task are terminal (eager)
Display() and Do() force enumeration
Ordering
ParallelQuery and ParallelAsyncQuery do not preserve order by default
Use .AsOrdered() or .WithOptions(preserveOrder: true) if ordering is required
Appendix A: Async Side-Effects in Parallel Pipelines
A common question is why ForEach(Func<T, Task>) is available for ParallelAsyncQuery but ❌ NOT for standard ParallelQuery.
The Limitation of PLINQ (ParallelQuery)
Standard PLINQ is designed for synchronous CPU-bound parallelism. It expects delegates to return void or a result immediately.
If you pass an async lambda to ForEach(Action<T>), it becomes an async void delegate.
Consequence: The pipeline will not wait for the asynchronous operation to complete. It will fire the task and immediately move to the next item.
Risk: Exceptions in async void methods can crash the entire process, and valid tasks may be cancelled prematurely when the main thread exits.
The Solution (ParallelAsyncQuery)
ParallelAsyncQuery was specifically architected to handle asynchronous I/O-bound parallelism.
It accepts Func<T, Task>, properly awaits each concurrent task, and manages concurrency limits (degree of parallelism).
This ensures that the pipeline waits for all side-effects (e.g., database writes, API calls) to complete before finishing.
Rule of Thumb:
Use ParallelQuery for CPU-intensive work (computations).
Use ParallelAsyncQuery for I/O-intensive work (network/disk operations).