ForEach

ForEachExpression represents a foreach loop over any IEnumerable or IEnumerable<T> collection. It generates standard loop IL equivalent to:

foreach ( var element in collection )
    body;

The expression handles enumerator acquisition, disposal of IDisposable enumerators, and typed element access automatically.


Factory Methods

using static Hyperbee.Expressions.ExpressionExtensions;
Overload Description
ForEach( Expression collection, ParameterExpression element, Expression body ) Basic foreach
ForEach( Expression collection, ParameterExpression element, Expression body, LabelTarget brk, LabelTarget cont ) With explicit break/continue labels
ForEach( Expression collection, ParameterExpression element, LoopBody body ) Body receives break/continue labels

The LoopBody delegate provides break and continue labels to the body builder:

public delegate Expression LoopBody( LabelTarget breakLabel, LabelTarget continueLabel );

Usage

Iterate a List

using static System.Linq.Expressions.Expression;
using static Hyperbee.Expressions.ExpressionExtensions;

var items = Constant( new[] { 1, 2, 3, 4, 5 } );
var item = Variable( typeof(int), "item" );
var sum = Variable( typeof(int), "sum" );

var forEachExpr = Block(
    [sum],
    Assign( sum, Constant( 0 ) ),
    ForEach(
        items,
        item,
        AddAssign( sum, item )
    ),
    sum
);

var lambda = Lambda<Func<int>>( forEachExpr );
var fn = lambda.Compile();
Console.WriteLine( fn() );  // 15

ForEach with Break

var item = Variable( typeof(int), "item" );
var first = Variable( typeof(int), "first" );

var forEachExpr = Block(
    [first],
    ForEach(
        items,
        item,
        ( brk, cont ) => Block(
            Assign( first, item ),
            Break( brk )         // capture first element and exit
        )
    ),
    first
);

ForEach with Continue

var item = Variable( typeof(int), "item" );

var forEachExpr = ForEach(
    items,
    item,
    ( brk, cont ) =>
        IfThenElse(
            Equal( Modulo( item, Constant( 2 ) ), Constant( 0 ) ),
            Continue( cont ),                              // skip even numbers
            Call( typeof(Console).GetMethod("WriteLine", [typeof(int)]), item )
        )
);

Inside an Async Block

var item = Variable( typeof(string), "item" );

var asyncBlock = BlockAsync(
    ForEach(
        Constant( new[] { "a", "b", "c" } ),
        item,
        Await( Call( typeof(MyService).GetMethod("ProcessAsync"), item ) )
    )
);

Notes

  • collection can be any expression whose type implements IEnumerable or IEnumerable<T>.
  • If the enumerator implements IDisposable, it is disposed in a generated try/finally block.
  • The element variable is scoped to the loop body and holds the current element on each iteration.
  • See For and While for other loop expressions.

© Stillpoint Software.

Hyperbee Expressions Docs