Etienne Fesser
Etienne Fesser

Reputation: 172

Assignment inside lambda expression

I made an extension which adds ForEach() method on ObservableCollection :

public static void ForEach<T>(this ObservableCollection<T> enumerable, Action<T> action)
{
    foreach (var item in enumerable)
        action(item);
}

When I use it, like this :

private bool Bar(int i)
{
    return i % 2 == 1;
}

private void Foo()
{
    Boolean ok = true;
    ObservableCollection<int> oc = new ObservableCollection<int> { 1, 2, 3, 4 };

    oc.ForEach(i => ok &= Bar(i));
    //ok is now false
}

I don't understand how does the ok Boolean take the value returned by the Bar() method which is executed by action(item) ?

Upvotes: 2

Views: 1300

Answers (2)

Justin Harvey
Justin Harvey

Reputation: 14672

You are applying &= which will and each result with the previos value of ok (as ok is not local to a single loop iteration, it is declared outside of the loop). In other words,

as the condition is only true for two values (1 and 3)

ok = true && false && true && false

which is false.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726489

Lambdas are allowed to modify variables that are in the scope of the code inside their bodies. You need to be very careful with this sort of code, because you do not always have full control over the timing of executing the lambdas.

For example, if you add an assignment to a lambda that you pass to a method with deferred execution, the side effect of that lambda (i.e. the assignment) would not be visible until the code of that lambda has actually executed.

Here is an example:

bool ok = true;
IEnumerable<int> res = new[] {1, 2, 3}.Where(i => ok &= (i == 2));
// ok is true here
IList<int> listRes = res.ToList();
// ok is false here

If you run this code, ok would remain true, even though the very first item of the source list would trigger an assignment of false to the ok variable. This wouldn't happen, however, until you enumerate res.

Upvotes: 2

Related Questions