即時実行と遅延実行

LINQを使った処理での遅延実行について、逆コンパイラの結果の違いから見ていきましょう。

即時実行

サンプル

Listを使ってキャッシュされたデータをループ処理する様子を見てみましょう。

using System;
using System.Collections.Generic;
using System.Linq;

class MyClass
{
    static void Main()
    {
        var nums = new List<int> { 3, 1, 5 };

        foreach (var num in nums)
        {
            Console.WriteLine(num);
        }
    }
}

逆コンパイラの結果

次のサンプルでブレイクポイントを設定してステップ実行すると、GraterThenTwo(int n)メソッドが都度呼び出されている様子がわかると思います。
Where拡張メソッドは、分析のために自作メソッドとなっています。

using System;
using System.Collections.Generic;

internal class MyClass
{
    private static void Main()
    {
        List<int> list = new List<int>();
        list.Add(3);
        list.Add(1);
        list.Add(5);
        List<int> list2 = list;
        List<int>.Enumerator enumerator = list2.GetEnumerator();
        try
        {
            while (enumerator.MoveNext())
            {
                int current = enumerator.Current;
                Console.WriteLine(current);
            }
        }
        finally
        {
            ((IDisposable)enumerator).Dispose();
        }
    }
}

遅延実行

サンプル

次のサンプルでデバッグでブレイクポイントを設定しステップ実行すると、LINQ処理が遅延評価(list内容が2より大きいか評価)する様子がわかります。

using System;
using System.Collections.Generic;
using System.Linq;

class MyClass
{
    static void Main()
    {
        var nums = new List<int> { 3, 1, 5 };
        var newNums = nums.Where(n => n > 2);

        foreach (var num in newNums)
        {
            Console.WriteLine(num);
        }
    }
}

逆コンパイラの結果

同様にブレイクポイントを設定してステップ実行すると、GraterThenTwo(int n)メソッドが都度呼び出されている様子がわかると思います。
Where拡張メソッドは、分析のために自作メソッドを呼び出しています。sharp

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

internal class MyClass
{
    [Serializable]
    [CompilerGenerated]
    private sealed class Compare
    {
        public static readonly Compare compare = new Compare();

        public static Func<int, bool> compInt;

        internal bool GraterThenTwo(int n)
        {
            return n > 2;
        }
    }

    private static void Main()
    {
        List<int> list = new List<int>();
        list.Add(3);
        list.Add(1);
        list.Add(5);
        List<int> source = list;
        IEnumerable<int> enumerable = Exexpansion.Where(source, Compare.compInt ?? (Compare.compInt = new Func<int, bool>(Compare.compare.GraterThenTwo)));
        IEnumerator<int> enumerator = enumerable.GetEnumerator();
        try
        {
            while (enumerator.MoveNext())
            {
                int current = enumerator.Current;
                Console.WriteLine(current);
            }
        }
        finally
        {
            if (enumerator != null)
            {
                enumerator.Dispose();
            }
        }
    }
}

static class Exexpansion
{
    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        foreach (var item in source)
        {
            if (predicate(item))
            {
                yield return item;
            }
        }
    }
}

C#

Posted by hidepon