Resharper, linq inside foreach loop
Resharper suggests using the top example in the bottom example. However, I am under the impression that a new list of items will be created first, and therefore all _executeFunc functions will be executed before the runstoredprocedure is called.
This is generally not a problem, however there are exceptions, and if my hypothesis is correct, my database will not update even though the functions have been started.
foreach (var result in rows.Select(row => _executeFunc(row)))
{
RunStoredProcedure(result)
}
or
foreach(var row in rows)
{
var result = _executeFunc(row);
RunStoredProcedure(result);
}
source to share
Operators in this case are semantically the same as Select
(and linq in general) use deferred execution of delegates. It will not run the declared queries until the result is implemented, and depending on how you write that query, it will do so in the correct sequence.
A very simple example:
var list = new List<string>{"hello", "world", "example"};
Func<string, string> func = (s) => {
Console.WriteLine(s);
return s.ToUpper();
};
foreach(var item in list.Select(i => func(i)))
{
Console.WriteLine(item);
}
leads to
hello
HELLO
world
WORLD
example
EXAMPLE
source to share
The first example _executeFunc(row)
will NOT be called first for every element in rows
before the loop starts foreach
. LINQ will defer execution. See this answer for details .
The order of events will be:
- Rate the first item in
rows
- Call
executeFunc(row)
in this item - Call
RunStoredProcedure(result)
- Repeat with next item in
rows
Now if your code was something like this:
foreach (var result in rows.Select(row => _executeFunc(row)).ToList())
{
RunStoredProcedure(result)
}
Then LINQ first needs to run .Select
on every item in rows
, because it .ToList()
invokes enumeration of the collection.
source to share
In the above example, the usage Select
will project the lines yielding
one at a time.
So,
foreach (var result in rows.Select(row => _executeFunc(row)))
basically the same as
foreach(var row in rows)
So Select does something like this
for each row in source
result = _executeFunc(row)
yield result
This output skips each line backward one by one (this is a little more complicated, but this explanation is sufficient for now).
If you did this instead
foreach (var result in rows.Select(row => _executeFunc(row)).ToList())
The call ToList()
will immediately return a list of lines, which means that _executeFunc () will indeed be called for every line before you I had the opportunity to call RunStoredProcedure()
.
Thus, what Resharper offers is indeed. To be honest, I'm sure the Jetbrains developers know what they are doing :)
source to share