カリー化で遊んでたら全然違うものになった
※最初はカリー化と称して全然違うものを書いてました。全面的に訂正しました、ごめんなさい。
C#3.0の拡張メソッドのカリー化、便利な使いどころを見つけようと遊んでいるうちにカリー化してない例になってしまったけど、現実的なLINQの使い方になっているので記録。
あらかじめLINQのクエリーを用意しておいて、whereの条件式だけ可変にする例です。
この例ではちょっと極端な例にしたかったので、where後、selectして表示する手続きまでまとめてみました。Lisp脳じゃないですねw
using System; using System.Collections.Generic; using System.Linq; class Program { delegate void FindAndAction( Func<Person, bool> f ); static void Main() { var persons = new[] { new Person { Name = "Wataru Abe", Gender = Gender.Male, IsActive = true }, new Person { Name = "Masao Sueda", Gender = Gender.Male, IsActive = true }, new Person { Name = "Sae Nakarai", Gender = Gender.Female, IsActive = true }, new Person { Name = "Shiori Yamamoto", Gender = Gender.Female, IsActive = true }, new Person { Name = "Satoshi Hatakeyama", Gender = Gender.Male, IsActive = false }, }; FindAndAction findAndPrintNames = f => persons.Where( f ) .Select( p => p.Name ) .ToList().ForEach( Console.WriteLine ); findAndPrintNames( p => p.IsActive ); Console.WriteLine(); findAndPrintNames( p => p.Gender == Gender.Female ); Console.ReadKey(); } } public enum Gender { Male, Female } class Person { public string Name { get; set; } public bool IsActive { get; set; } public Gender Gender { get; set; } }
匿名型を使わずPersonクラスを作ったのは、型がないとdelegateの定義が書けなかったため。もしかしたら、こないだNyaRuRuさんが書いてた記事のあたりで、どうにかなるのかもしれません。
もう一つ。Personはimmutableにしたかったけど、自動プロパティを{get;}だけにしようとしたらエラーでした。泣く泣くmutableに。{get;}とできたところでimmutableになっているのかどうかは、要検討。
NyaRuRuさんにコメントで教えてもらったToListをさっそく使っています。実験コードには超便利。NyaRuRuさんのコメントにあるようにその場で実行されたりインスタンス化されたりと、LINQの利点を台無しにしてしまうかもしれないのでご注意を。
ちなみにカリー化とは
Func<Func<Person, bool>, IEnumerable<Person>> where = persons.Where;
こんな感じ。Whereは2変数を取ります(1変数を取るインスタンスメソッドのように見えるけど)。そのうち一つ目の引数をがっちり固定して、それに名前を付けて持ち運べるってのが、C#3.0のカリー化です。もう一つの引数は開いたまま。Func