C#におけるforeach文とfor文による添え字アクセスのパフォーマンス検証

C#においてforeach文とfor文で添え字アクセスする方法のどちらを用いたほうがパフォーマンスが上がるのかについて気になっていました。

普段良く使う配列(Arrayクラス)とListクラスについて、foreach文とfor文によるシーケンシャルアクセスの速度を検証してみました。

今回用いたプログラムは以下の通りです。

    class Program
    {
        static void Main(string[] args)
        {
            const int ELEM_NUM = 1000000;

            object[] objArray = new object[ELEM_NUM];
            for (int i = 0; i < ELEM_NUM; ++i)
            {
                objArray[i] = new object();
            }

            System.Console.WriteLine("Array");
            Test(objArray);


            List<object> objList = new List<object>();
            for (int i = 0; i < ELEM_NUM; ++i)
            {
                objList.Add(new object());
            }

            System.Console.WriteLine("");
            System.Console.WriteLine("List");
            Test(objList);


            System.Console.ReadLine();
        }

        public static void Test<t>(IList<t> objList)
        {
            const int LOOP_NUM = 100;

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            object obj;

            // foreach
            sw.Restart();

            for (int i = 0; i < LOOP_NUM; ++i)
            {
                foreach (var elem in objList)
                {
                    obj = elem;
                }
            }

            sw.Stop();
            System.Console.WriteLine("foreach time = " + sw.Elapsed);


            // index
            sw.Restart();

            for (int i = 0; i < LOOP_NUM; ++i)
            {
                for (int j = 0; j < objList.Count; ++j)
                {
                    obj = objList[j];
                }
            }

            sw.Stop();
            System.Console.WriteLine("index   time = " + sw.Elapsed);
        }
    }

実行結果は以下のようになりました。

■Debug版

Array
foreach time = 00:00:00.9181903
index   time = 00:00:01.3635538

List
foreach time = 00:00:01.5507959
index   time = 00:00:01.4055962

■Release版

Array
foreach time = 00:00:00.6986892
index   time = 00:00:01.1227786

List
foreach time = 00:00:01.3271968
index   time = 00:00:00.9576023

上記より、配列ではforeach文を用いたほうが速いようです。
Listクラスではfor文による添え字アクセスのほうが速いようです。

線形リストへの要素アクセスは通常でo(n)の処理コストがかかるため、ちょっと意外でした。
恐らく、シーケンシャルアクセスの場合は内部的に直近の要素への参照を保持しているなどで対策を施しているのかもしれません。
foreach文の場合はcollection.MoveNext()メソッドを呼び出してからcollection.Currentを呼び出す必要があるため、このワンクッションで時間がかかっている・・・のかもしれません。

foreachとfor文による添え字アクセスはどちらもそれほどパフォーマンスが劇的に低下することは無いので、状況に応じて使いやすいほうを使うので問題ないと思います。