うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【C#】for と foreach

パフォーマンス

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 のほうが若干早かった

f:id:hacchi_man:20200613044231p:plain

ループ中の要素の置き換え

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; }
    }