あなたが何を求めているのか正確にはわかりません。Expression
しかし、少なくとも、メインストリームの .NET 言語 (C#、VB.NET) の言語機能であるラムダ関数とラムダ関数の違いについて、いくつかの洞察を提供することができます。
基本的に、ラムダ関数は、別の関数のスコープ内で宣言できる匿名 (名前のない) 関数です。C# (言語バージョン 3) では、次のように宣言されます。
(
パラメータリスト 関数本体)
=>
例えば:
void Foo()
{
// two equivalent lambda functions with one double parameter 'x' each:
var square = (double x) => x * x;
var square2 = (double x) => { return x * x; };
// lambda function that doesn't take any arguments:
var doSomething = () => { Console.WriteLine("Hello."); }
}
(たとえば、ラムダ関数の名前ではなく、それを参照する変数の名前であることに注意してくださいsquare
。ラムダ関数自体には、メソッドのような名前はありませんvoid Foo()
!)
匿名デリゲートと呼ばれる、非常によく似たことが C# バージョン 2 で既に可能でした。
delegate(double x) { return x * x; } // is equivalent to: (double x) => x * x
LINQ を使用して .NET に式System.Linq.Expressions
が追加されました (名前空間内)。基本的に、 C# や VB.NET などで表現できるあらゆる計算を抽象構文木(AST)として記述する単純なデータ構造です。たとえば、次のとおりです。
// case 1. IEnumerable<int>:
IEnumerable<int> xs = ...;
IEnumerable<int> queryXs = from x in xs where x > 0 select x;
// case 2. IQueryable<int>:
IQueryable<int> ys = ...;
IEnumerable<int> queryYs = from y in ys where y > 0 select y;
これら 2 つのクエリys
は、タイプがIQueryable<int>
ではなく であることを除いて、同じですIEnumerable<int>
。C# コンパイラは、上記の 2 つのクエリを別のコードに変換します。
// case 1. IEnumerable<int>:
IQueryable<int> xs = ...;
IEnumerable<int> queryXs = xs.Where<int>(delegate (int x) { return x > 0; });
// case 2. IQueryable<int>:
IEnumerable<int> ys = ...;
ParameterExpression yParameter = Expression.Parameter(typeof(int), "y");
IEnumerable<int> queryYs.Where<int>(
Expression.Lambda<Func<int, bool>>(
Expression.GreaterThan(
yParameter,
Expression.Constant(0, typeof(int))),
new ParameterExpression[] { yParameter }));
後者を調べると、 のクエリについてIQueryable<int>
、コンパイラは解析されたクエリを、クエリを記述するデータ構造として出力したことがわかります。一方、 に対するクエリのIEnumerable<int>
場合は、クエリを実行するコードを出力するだけです。コンパイラは、解析したものを式ツリーとして型だけで生成するという特別な魔法を実行することがわかりましたIQueryable<T>
。
式をIQueryable<T>
使用すると、実行時にクエリを分析し、実際に実行する前に最適化やその他の変換を実行できます。これは、インテリジェントで最適化された SQL クエリを作成するために、LINQ to SQL などで頻繁に使用されます。
データベースが、一部の列x
が > 0 であるすべての行を求められたと想像してください。
データベースがIEnumerable<int>
(実際には大幅に単純化されていることはわかっていますが、ご容赦ください) の場合、すべての行を取得してから、.Where(delegate (int x) { ... })
メソッドによってフィルター処理する必要があります。
データベースが の場合、IQueryable<int>
コンパイラExpression
による出力は実行時に分析され、SQL クエリに変換されます。これにより、適切なWHERE x > 0
句が含まれ、必要な行のみがすぐに生成されます。
式ツリーの内部構造や構文解析に興味がある場合は、Bart De Smet による詳細なブログ シリーズを参照してください。最初はIQueryable tales - LINQ to LDAP - Part 0: Introductionです。