2014年06月20日

ActionやFuncを匿名でかっこ良く書くお話

すごく便利に思えるんだけど、どこにも書いてなかったお話。

ActionやFuncを書くとき、以下のようにしていませんか?

var act = new Action(() =>
{
Console.WriteLine("引数なし、戻り値なしのアクションを実行っ");
});
act();

はい、決して悪くは無いのですが、actって変数を一々宣言して、代入して、act経由で関数を実行しないといけないって、ちょっと面倒じゃないですか?
優秀なJSerならこう思うはずです、匿名Actionを使わせろ、と。(優秀なC#erは思わないかもしれませんw

今回のお話は、こんなお話です。

実はC#で匿名Actionを使うことは可能です。

ナ、ナンダッテー!!!

あまりC#っぽいスタイルではないからなのか、あまり大きな声で紹介されてないやり方みたいです。
自分で気づくまでは全く知らなかった(というか考えすらしなかった)ので、個人的にはかなりの衝撃なのですが、出来ました。

そのコードは以下のとおりです。

new Action(() =>
{
Console.WriteLine("引数なし、戻り値なしのアクションを実行っ");
})();

先ほどと違って、Action(○○);ではなく、Action(○○)();という形になっています。
これは、act();のように、Actionの末尾に、関数実行の()を付けただけです。
実にJSらしい、JSらしいぞ書き方だぞC#・・・!

もちろん、Actionではなく、Funcでも出来ます。
あ、Funcってのは戻り値が存在するActionって思ってくれたらおっけーね。

int val = new Func<int>(() =>
{
return 18;
})();
Console.WriteLine("がおさん" + val + "さい"); //がおさん18さい

こんな感じです。ね?簡単でしょ?

なので、Funcを返すFuncなんてのも定義して、匿名でゴニョゴニョするとこんなことも出来ます。

var Counter = new Func<Func<int>>(() =>
{
int cnt = 0;
return new Func<int>(() =>
{
return cnt++; //呼ばれる度に上位スコープのcntの値を1増やす
});
})(); //←即時実行して、Func<int>型のなにかをCounterに代入

Console.WriteLine(Counter()); //0
Console.WriteLine(Counter()); //1
Console.WriteLine(Counter()); //2

どうです?とても変態チックでしょう。私は大好きです(紳士)
JSに慣れ親しんでる人から見たら「何だ関数を返す関数か」、って感じでしょうがC#ではめっちょ見慣れない形かと思います。

まあこの関数を返す関数、俗にクロージャって呼ばれるものが何に使えるのか、って言われるとすっげー悩むのですが。

で、でも!asnc,awaitとこの匿名Actionを組み合わせたらちょっと便利なことがあってね!!

new Action(async () =>
{
await Task.Run(() =>
{
//糞重い処理奴〜〜〜〜〜
});
})();
Console.WriteLine("↑は非同期的にやってくれるから、こっちに先に到達してくれるよ!");

こんな使い方が出来たり。ね?便利でしょ?(吐血

結論:ラムダ式とか即時実行Actionを駆使してゴニョゴニョするのって、まあかなりC#erとして異端だと思うけど、面白いと思うんですっ。便利だと思うんですっ。流行れ、とまでは言わないが、こういうやり方もあるよってのを紹介してみました。おわりっ
posted by がお at 19:19| Comment(0) | C# | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

×

この広告は1年以上新しい記事の投稿がないブログに表示されております。