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