MSM i somekind wątpią w moje twierdzenia o gorszej wydajności foreach w stosunku do for. Żeby nie było że coś mi się przyśniło na szybko postaram się nakreślić problem.
Niech przykładem będzie taki oto prosty program.
class Program
{
static Random rand = new Random((int)DateTime.Now.Ticks);
static List<T> CreateTestList<T>(int size, Func<T> newItem)
{
List<T> list = new List<T>(size);
for (int i = 0; i < size; i++)
list.Add(newItem());
return list;
}
static void Test<T>(int size, Func<T> newItem)
{
List<T> l1 = CreateTestList<T>(size, newItem);
DateTime d1 = DateTime.UtcNow;
for (int i = 0; i < l1.Count; i++)
{ }
DateTime d2 = DateTime.UtcNow;
foreach (var x in l1)
{ }
DateTime d3 = DateTime.UtcNow;
Console.WriteLine("for : {0,-10}", (d2 - d1).TotalMilliseconds);
Console.WriteLine("foreach: {0,-10}", (d3 - d2).TotalMilliseconds);
}
static void Main(string[] args)
{
int size = 1000000;
Console.WriteLine("int - value type");
Test<int>(size, () => rand.Next());
Console.WriteLine("FooClass1 - reference type");
Test<FooClass1>(size, () => new FooClass1 { I1 = rand.Next() });
Console.WriteLine("DateTime - value type");
Test<DateTime>(size, () => DateTime.Now);
Console.WriteLine("string - refernece type, immutable type");
Test<string>(size, () => rand.Next().ToString());
}
}
public class FooClass1
{
public int I1 { get; set; }
}
Co jest przyczyną zła jeśli chodzi o foreach? Enumerator!
Tak reflector pokazuje zdeassemblowany kawałek dla foreach.
using (List<int>.Enumerator enumerator = list.GetEnumerator())
{
while (enumerator.MoveNext())
{
CS$1$0000 = enumerator.Current;
}
}
i jeszcze Enumerator<T>.MoveNext()
public bool MoveNext()
{
List<T> list = this.list;
if ((this.version == list._version) && (this.index < list._size))
{
this.current = list._items[this.index];
this.index++;
return true;
}
return this.MoveNextRare();
}
Myślę że dla wszystkich którzy przeczytają ten kod wszystko będzie jasne.
Poza tym jeśli ja nie jestem autorytetem :) to proponuję przeczytać
http://msdn.microsoft.com/en-us/library/ms973839.aspx cześć Use For Loops for String Iteration—version 1
"foreach is a very powerful tool, since it acts as a general-purpose enumerator over many types. The tradeoff for this generalization is speed, and if you rely heavily on string iteration you should use a For loop instead."
oraz http://msdn.microsoft.com/en-us/library/ms998547 część Iterating and Looping "Use for instead of foreach in performance-critical code paths".
Właściwie to żeby nie powielać tego co już ludzie napisali dawno temu podam link do artykułu o wydajności różnych typów iterowania po List<T>:
http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx
Oczywiście różnice uwidaczniają się przy dużych kolekcjach. Ale warto zdawać sobie z tego sprawę.