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:
- Let
O
be the result of callingToObject
passing thethis
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:
In the case above,
ToList()
wastes time and memory, because it first does the same thing as the initialforeach
, builds a list from it, and thenforeach
s that list. The differences will be somewhere between trivial and preventing the code from ever working, depending on the size of the results.However, in the case where you are going to repeatedly do
foreach
on the same results, or otherwise use it repeatedly, the then while theforeach
only runs the query once, the nextforeach
runs it again. If the query is expensive, then theToList()
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
Ternary Operator Vb VS C#: Why Resolves Nothing to Zero
How to Set Dynamic Value in My Attribute
Should I Take Ilogger, Ilogger<T>, Iloggerfactory or Iloggerprovider for a Library
How to Set the Color of a Selected Row in Datagrid
How to Select Only the Records with the Highest Date in Linq
Generic List - Moving an Item Within the List
How to Retrieve Disk Information in C#
Using SQLdataadapter to Insert a Row
Preprocessor Directive in C# for Importing Based on Platform
C# Regular Expressions, String Between Single Quotes
Finding a Subsequence in Longer Sequence
Why \B Does Not Match Word Using .Net Regex