かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

LINQを、ちょっとカスタマイズ?

LINQって結局メソッド呼び出しに展開されている。
例えば下のようなものがあるとすると

var data = new[] {1, 2, 3, 4, 5};
var ret = from i in data
          select i * i;

こんな感じのメソッド呼び出しに展開される。

var data = new[]{1, 2, 3, 4, 5};
var ret = data.Select(i => i * i);

Selectは、多分System.Linq.Enumerableあたりで用意されてる拡張メソッド。
中身がどうなってるかは知らない。


ってわけで、System.Linq.EnumerableにあるSelectメソッドより優先度の高い拡張メソッドを作ってやれば、LINQの動きをちょびっと変える事ができる。
例えば、こんなクラスを用意して

class MyEnumerable<T> : IEnumerable<T>
{
    public T[] data;

    public MyEnumerable(T[] data)
    {
        this.data = data;
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (var val in data)
        {
            yield return val;
        }
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

こんな拡張メソッドを用意する。

static class MyEnumerableExtensions
{
    public static MyEnumerable<TResult> Select<TSource, TResult>(
        this MyEnumerable<TSource> e, Func<TSource, TResult> selectFunc)
    {
        Console.WriteLine("ここを通った!!");
        IList<TResult> results = new List<TResult>();
        foreach (var i in e)
        {
            results.Add(selectFunc(i));
        }
        return new MyEnumerable<TResult>(results.ToArray());
    }
}

そんで、こんなMainメソッドを実行すると

class Program
{
    static void Main(string[] args)
    {
        MyEnumerable<int> e = new MyEnumerable<int>(new[] { 1, 2, 3, 4, 5, 6, 7 });
        var ret = from i in e
                  select i * i;
        foreach (var i in ret)
        {
            Console.WriteLine(i);
        }
    }
}

実行結果がこうなる!

ここを通った!!
1
4
9
16
25
36
49

自前で用意したEnumerableExtensions::Selectメソッドを通ったっぽいね!
超頑張れば色々出来そうだ。