C# LINQのクエリ式
C#5.0の言語仕様で追加された、非同期処理を同期的に記述できるasync/awaitメソッドについても興味があるのですが、次々と新しい仕様を取り込むC#自体にとても興味があります。その中でもLINQはとても面白い深い存在なので、ちょっとまとめてみたいと思います。
環境: VisualStudio 2012 / Windows 8
プロジェクトは、C#コンソールアプリケーションです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinqTest
{
class Program
{
static void Main(string[] args)
{
var q0 = Enumerable.
Select(Enumerable.Where(Enumerable.Range(0, 10), p => p > 5), q => q * q);
foreach (var v in q0)
{
Console.Write("q0:{0}\n", v);
}
var q1 = Extensions.MyAdd(Enumerable.
Select(Enumerable.Where(Enumerable.Range(0, 10), p => p > 5), q => q * q), 2);
foreach (var v in q1)
{
Console.Write("q1:{0}\n", v);
}
var q2 = Enumerable.
Range(0, 10).Where(p => p > 5).Select(q => q * q);
foreach (var v in q2)
{
Console.Write("q2:{0}\n", v);
}
var q3 = Enumerable.
Range(0, 10).Where(p => p > 5).Select(q => q * q).MyAdd(2);
foreach (var v in q3)
{
Console.Write("q3:{0}\n", v);
}
var q4 = from p in Enumerable.Range(0, 10) where p > 5 select p * p;
foreach (var v in q4)
{
Console.Write("q4:{0}\n", v);
}
Console.Read();
}
}
public static class Extensions
{
public static IEnumerable<int> MyAdd(
this IEnumerable<int> x, int a)
{
foreach (int v in x)
{
yield return v + a;
}
}
}
}
q0,q2,q4とq1,q3は、それぞれ同じ値を出力します。
36,49,64,81
38,51,66,83
クエリ式の3つのバリエーションのテストをしました。
1つ目が、スタティックメソッドの入れ子、2つ目がメソッドチェーン、3つ目がクエリ式です。
そして、スタティックメソッド、メソッドチェーンについては、MyAddという拡張メソッドを定義してそれを利用しています。(クエリ式でもやる方法はあるのかな? Rxを使う?)
言語仕様がどんどん変化している様子をまとめてみました。
オブジェクト指向言語の次の言語として注目されている関数型言語というものがありますが、新しいもの好きの私ももれなくHaskellとか勉強したことがありました。しかしどのように使うと便利なのか等、なかなかその概念が理解できませんでした。このLINQを触っていると、関数型言語の特徴の一つの遅延評価というものが、とてもよく理解できます。上の例でMyAddメソッドがまさにそれにあたります。このメソッド中のyield return という構文が、それを実現しているのですが、これは必要になったときに実行されます。必要になったときというのは、定義されたときではないということです。もともと関数というのは、宣言・定義・記述しただけでは実行されず、呼び出されたとき・使われたときに実行するので、関数型という言い方も腑に落ちるというわけです。
あと、冒頭に非同期処理のことを少し触れましたが、この非同期を記述するのにもLINQを使うことができるようです。ReactiveExtensions(以下Rx)と呼ばれるものですが、これはこれでとても興味深いので、また別の機会に掘り下げたいと思います。このRxの非同期処理のプログラムを見ていると、JavaScriptのjQuery.Deferredに似ています。もともとAjaxという非同期処理を有名にしたJavaScriptなので、これも腑に落ちるところですが、jQueryの非同期処理を連続して実行してもコードが見やすいしくみになっています。(メソッドチェーンという言い方も、私はjQueryのことをイメージして使っています。)
WindowsストアアプリのAPIがほとんど非同期になるということからも、このようなトレンドはどの言語も取り入れているということなのでしょう。
関数型言語にいきなりジャンプアップするのは難しいかもしれませんが、このようにLINQとかRxで徐々に体を慣らしていくと、いいのかもしませんね。オブジェクト指向もRubyで学習すると理解がしやすいという意見もあったりしますし、いろんな側面から技術を見るということは大切なことかもしれません。