かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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メソッドを通ったっぽいね!
超頑張れば色々出来そうだ。