In .NET, using "foreach" to iterate an instance of IEnumerable will create a copy? So should I prefer to use "for" instead of "foreach"?
I wrote some code to testify this:
struct ValueTypeWithOneField { private Int64 field1; } struct ValueTypeWithFiveField { private Int64 field1; private Int64 field2; private Int64 field3; private Int64 field4; private Int64 field5; } public class Program { static void Main(string[] args) { Console.WriteLine("one field"); Test<ValueTypeWithOneField>(); Console.WriteLine("-----------"); Console.WriteLine("Five field"); Test<ValueTypeWithFiveField>(); Console.ReadLine(); } static void Test<T>() { var test = new List<T>(); for (int i = 0; i < 5000000; i++) { test.Add(default(T)); } Stopwatch sw = new Stopwatch(); for (int i = 0; i < 5; i++) { sw.Start(); foreach (var item in test) { } sw.Stop(); Console.WriteLine("foreach " + sw.ElapsedMilliseconds); sw.Restart(); for (int j = 0; j < test.Count; j++) { T temp = test[j]; } sw.Stop(); Console.WriteLine("for " + sw.ElapsedMilliseconds); sw.Reset(); } }}
And this is the result that I got after I ran the code:
one field foreach 68 for 72 foreach 68 for 72 foreach 67 for 72 foreach 64 for 73 foreach 68 for 72 ----------- Five field foreach 272 for 193 foreach 273 for 191 foreach 272 for 190 foreach 271 for 190 foreach 275 for 188
As we can see in the result, "foreach" always takes more time than "for".
So should I prefer to use "for" instead of "foreach" when iterating through a generic collection of value type?
Note: thanks for the reminder, I edited the code and result. but still, foreach is running slower than for.
Only use the for-each loop when you want to loop through all the values in an array or list. If you only want to loop through part of an array or list use a for loop instead. Also use a for loop instead of a for-each loop if you want to change any of the values in the array or list.
The difference between for and foreach in C# is that for loop is used as a general purpose control structure while foreach loop is specifically used for arrays and collections. In brief, both helps to execute code repeatedly but foreach loop is more specific to arrays and collections.
The IEnumerator interface provides iteration over a collection-type object in a class. The IEnumerable interface permits enumeration by using a foreach loop.
foreach loop in C# C# foreach loop is used to iterate through items in collections (Lists, Arrays etc.). When you have a list of items, instead of using a for loop and iterate over the list using its index, you can directly access each element in the list using a foreach loop.
Your question is way, way too complex. Break it down.
Does using “foreach” to iterate a sequence of value types create a copy of the sequence?
No.
Does using "foreach" to iterate a sequence of value types create a copy of each value?
Yes.
Does using "for" to do an equivalent iteration of an indexed sequence of value types create a copy of each value?
Usually, yes. There are things you can do to avoid the copying if you know special things about the collection, like for instance that it is an array. But in the general case of indexed collections, indexing the sequence returns a copy of the value in the sequence, not a reference to a storage location containing the value.
Does doing anything to a value type make a copy of the value?
Just about. Value types are copied by value. That's why they're called value types. The only things that you do to value types that do not make a copy are calls to methods on the value type, and passing a value type variable using "out" or "ref". Value types are copied constantly; that's why value types are often slower than reference types.
Does using "foreach" or "for" to iterate a sequence of reference type copy the reference?
Yes. The value of an expression of reference type is a reference. That reference is copied whenever it is used.
So what's the difference between value types and reference types as far as their copying behaviour is concerned?
Value types are copied by value. Reference types copy the reference but not the thing being referred to. A 16-byte value type copies 16 bytes every time you use it. A 16 byte reference type copies the 4 (or 8) byte reference every time you use it.
Is the foreach loop slower than the for loop?
Often it is. The foreach loop is often doing more work, in that it is creating an enumerator and calling methods on the enumerator, instead of just incrementing an integer. Integer increments are extremely fast. Also don't forget that the enumerator in a foreach loop has to be disposed, and that can take time as well.
Should I use the for loop instead of the foreach loop because the for loop is sometimes a few microseconds faster?
No. That's dumb. You should make smart engineering decisions based on customer-focussed empirical data. The extra burden of a foreach loop is tiny. The customer will probably never notice. What you should do is:
Odds are extremely good that if you have a performance problem, changing a foreach loop to a for loop will make no difference whatsoever to your problem. Write the code the way it looks clear and understandable first.
Your test is not accurate; in the foreach
version, you're actually spinning up the enumerator and retrieving each value from the list (even though you aren't using it). In the for
version, you aren't doing anything with the list at all, other than looking at its Count
property. You're essentially testing the performance of an enumerator traversing a collection compared to incrementing an integer variable an equivalent number of times.
To create parity, you'd need to declare a temporary variable and assign it in each iteration of the for
loop.
That being said, the answer to your question is yes. A copy of the value will be created with every assignment or return
statement.
This pseudocode breakdown should explain why foreach
is somewhat slower than using for
in this particular instance:
foreach
:
try { var en = test.GetEnumerator(); //creates a ListEnumerator T item; while(en.MoveNext()) // MoveNext increments the current index and returns // true if the new index is valid, or false if it's // beyond the end of the list. If it returns true, // it retrieves the value at that index and holds it // in an instance variable { item = en.Current; // Current retrieves the value of the current instance // variable } } finally { }
for
:
int index = -1; T item; while(++index < test.Count) { item = test[index]; }
As you can see, there's simply less code in the for
implementation, and foreach
has a layer of abstraction (the enumerator) on top of the for
. I wrote the for
using a while
loop to show the two versions in a similar representation.
You're talking about a trivial difference in execution time. Use the loop that makes the code clearer and smaller, and in this circumstance that looks like foreach
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With