パフォーマンス
0~10000までを加算して計測する
private class Test { public int Value; } private void Main() { List<Test> _list = Enumerable.Range(0, 10000).Select(i => new Test(){Value = i}).ToList(); var sum = 0; Profiler.BeginSample("ProfileFor"); for (var i = 0; i < _list.Count; ++i) { sum += _list[i].Value; } Profiler.EndSample(); sum = 0; Profiler.BeginSample("ProfileForeach"); foreach (var t in _list) { sum += t.Value; } Profiler.EndSample(); }
結果、そこまで大きな差はなかったが for のほうが若干早かった
ループ中の要素の置き換え
for も foreach も ジェネリッククラスの要素であれば値の差し替えが可能です
for (var i = 0; i < _list.Count; ++i) { _list[i].Value = 100; } foreach (var t in _list) { t.Value = 100; }
しかし 要素自体の書き換えは for は 可能ですが foreach ではできません
下記の処理を記述すると Cannot assign to 't' because it is a 'foreach iteration variable'
のコンパイルエラーが表示されます
List<int> _list = Enumerable.Range(0, 100).ToList(); for (var i = 0; i < _list.Count; ++i) { _list[i]= 100; } foreach (var t in _list) { t = 100; }
foreach の展開
foreach は コンパイル時に下記のように変換されます
foreach (var t in _list) ; // 実際にはこんな感じなる var e = _list.GetEnumerator(); while (e.MoveNext()) { try { var current = e.Current; } finally { e.Dispose(); } }
この際 Current
は 読み取り専用のため値の書き換えができなくなっています
[Serializable] public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable { public T Current { get; } }