Does Foreach Evaluate the Array at Every Iteration

Does foreach evaluate the array at every iteration?

I just mocked your code with this

foreach(var v in Enumerable.Range(1,10).Skip(1))
v.Dump();

And here is the IL generated.

IL_0001:  nop         
IL_0002: ldc.i4.1
IL_0003: ldc.i4.s 0A
IL_0005: call System.Linq.Enumerable.Range
IL_000A: ldc.i4.1
IL_000B: call System.Linq.Enumerable.Skip//Call to Skip
IL_0010: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator
IL_0015: stloc.1 // CS$5$0000
IL_0016: br.s IL_0026
IL_0018: ldloc.1 // CS$5$0000
IL_0019: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current
IL_001E: stloc.0 // v
IL_001F: ldloc.0 // v
IL_0020: call LINQPad.Extensions.Dump
IL_0025: pop
IL_0026: ldloc.1 // CS$5$0000
IL_0027: callvirt System.Collections.IEnumerator.MoveNext
IL_002C: stloc.2 // CS$4$0001
IL_002D: ldloc.2 // CS$4$0001
IL_002E: brtrue.s IL_0018
IL_0030: leave.s IL_0042
IL_0032: ldloc.1 // CS$5$0000
IL_0033: ldnull
IL_0034: ceq
IL_0036: stloc.2 // CS$4$0001
IL_0037: ldloc.2 // CS$4$0001
IL_0038: brtrue.s IL_0041
IL_003A: ldloc.1 // CS$5$0000
IL_003B: callvirt System.IDisposable.Dispose
IL_0040: nop
IL_0041: endfinally

As you can see Skip is called only once.

Equivalent c# code would look something like this

IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();//Get the enumerator
try
{
int m;//This variable is here prior to c#5.0
while(e.MoveNext())
{//int m; is declared here starting from c#5.0
m = (int)(int)e.Current;
//Your code here
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}

Consider the below code, If foreach calls VeryLongRunningMethodThatReturnsEnumerable at each iteration then that would be nightmare. Huge flaw in the design of the language. Fortunately it doesn't do that.

foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable())
{
//Do something with that obj
}

Does using a LINQ statement in a foreach re-evaluate the statement on each iteration

This sample should give you all the answers you seek:

Code

using System;
using System.Linq;

public class Test
{
public static void Main()
{
// Create sequence of integers from 0 to 10
var sequence = Enumerable.Range(0, 10).Where(p =>
{
// In each 'where' clause, print the current item.
// This shows us when the clause is executed
Console.WriteLine(p);

// Make sure every value is selected
return true;
});

foreach(var item in sequence)
{
// Print a marker to show us when the loop body is executing.
// This helps us see if the 'where' clauses are evaluated
// before the loop starts or during the loop
Console.WriteLine("Loop body exectuting.");
}
}
}

Output

0
Loop body exectuting.
1
Loop body exectuting.
2
Loop body exectuting.
3
Loop body exectuting.
4
Loop body exectuting.
5
Loop body exectuting.
6
Loop body exectuting.
7
Loop body exectuting.
8
Loop body exectuting.
9
Loop body exectuting.

Conclusion

The Where clause is evaluated once, for the current element, at the start of each loop iteration.

Does the function get called for every iteration of foreach loop when used it instead of an predefined array in a foreach loop?

filter_list() will be called only once, it's return value will be temporarily stored in memory, and iterated on.

It's fine to do it this way - if you'll need the results of filter_list() somewhere else in the code you should store it in a variable so it doesn't need to be re-executed later.

Does using a function in foreach loop caches the result, or calls the function each time?

No, your test is conclusive.

It makes no sense for it to evaluate the first expression any more than once. It's the basic premise of a foreach loop.

A for loop has three arguments, and it does evaluate the second and third each iteration.

Is the array creation happening on every foreach loop?

No, neither language splits the string every time (that would be absurd).

From the PHP manual:

On each iteration, the value of the current element is assigned to
$value and the internal array pointer is advanced by one (so on the
next iteration, you'll be looking at the next element).

Note the reference to the internal array pointer. If each iteration operated on a distinct array, changing the internal array pointer would be meaningless.

From the ES5 annotated reference:

When the forEach method is called with one or two arguments, the
following steps are taken:

  1. Let O be the result of calling ToObject passing the this value as the argument.

Here O represents the object being iterated on; this result is only calculated once.

Does foreach execute the query only once?

Now, with LINQ's deferred execution, would a subsequent foreach loop execute the query only once or for each turn in the loop?

Yes, once for the loop. Actually, it may execute the query less than once - you could abort the looping part way through and the (num % 2) == 0 test wouldn't be performed on any remaining items.

Or, in other words, would there be any difference if I had:

foreach (int num in numQuery.ToList())

Two differences:

  1. In the case above, ToList() wastes time and memory, because it first does the same thing as the initial foreach, builds a list from it, and then foreachs that list. The differences will be somewhere between trivial and preventing the code from ever working, depending on the size of the results.

  2. However, in the case where you are going to repeatedly do foreach on the same results, or otherwise use it repeatedly, the then while the foreach only runs the query once, the next foreach runs it again. If the query is expensive, then the ToList() approach (and storing that list) can be a massive saving.

Does the foreach loop in C# guarantee an order of evaluation?

For arrays (note that System.Array implements IEnumerable), it will access elements in order. For other types (IEnumerable, or having GetEnumerator), it accesses elements in the order provided, through alternating MoveNext and Current calls.

The standard states (ECMA-334 §13.9.5):

"The order in which foreach traverses
the elements of an array, is as
follows: For single-dimensional arrays
elements are traversed in increasing
index order, starting with index 0 and
ending with index Length – 1. For
multi-dimensional arrays, elements are
traversed such that the indices of the
rightmost dimension are increased
first, then the next left dimension,
and so on to the left."

java: how many times is the collection expression evaluated in a foreach

because it is equivalent to using an iterator, it is equivalent to calling the collections' . iterator() method, and it is called once.

Is the condition in a for loop evaluated each iteration?

Yes Count will be evaluated on every single pass. The reason why is that it's possible for the collection to be modified during the execution of a loop. Given the loop structure the variable i should represent a valid index into the collection during an iteration. If the check was not done on every loop then this is not provably true. Example case

for ( int i = 0; i < collection.Count; i++ ) {
collection.Clear();
}

The one exception to this rule is looping over an array where the constraint is the Length.

for ( int i = 0; i < someArray.Length; i++ ) {
// Code
}

The CLR JIT will special case this type of loop, in certain circumstances, since the length of an array can't change. In those cases, bounds checking will only occur once.

Reference: http://blogs.msdn.com/brada/archive/2005/04/23/411321.aspx

What happens in the foreach loop, which outputs the values of an array?

Your DaysOfTheWeek implements the interface IEnumerable. If you look at theforeach-documentation, you see that foreach works with something that implements IEnumerable (technically it works with everything that has an appropriate GetEnumerator method, see comments below).

When you implement IEnumerable you basically promise, that you also implement a (public) method called GetEnumerator. Since the foreach knows that this method is there, it will use it to iterate over/obtain your string values.



Related Topics



Leave a reply



Submit