式のコンパイルと実行
式ツリーを実行可能なデリゲートに変換します。
「式のコンパイルと実行」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
ツリーからデリゲートへ
式ツリーは、コンパイルするまでデータにすぎません。Expression<TDelegate>.Compile() は、ツリーを呼び出し可能な実際のデリゲートに変換します。
using System;
using System.Linq.Expressions;
Expression<Func<int, int>> tree = x => x + 1;
Func<int, int> fn = tree.Compile();
Console.WriteLine(fn(5)); // 6手動で構築したツリーをコンパイルする
手動で構築したツリーも同じ方法でコンパイルでき、動作するデリゲートが生成されます。
using System;
using System.Linq.Expressions;
var x = Expression.Parameter(typeof(int), "x");
var body = Expression.Multiply(x, Expression.Constant(3));
var lambda = Expression.Lambda<Func<int, int>>(body, x);
var fn = lambda.Compile();
Console.WriteLine(fn(4)); // 12結果を呼び出す
コンパイル済みのデリゲートは他のデリゲートと同じように動作します。呼び出したり、保存したり、受け渡したりできます。
using System;
using System.Linq.Expressions;
Expression<Func<int, int, int>> addExpr = (a, b) => a + b;
var add = addExpr.Compile();
Console.WriteLine(add(2, 3)); // 5
Console.WriteLine(add(10, 20)); // 30コンパイルは無料ではない
コンパイルには実行時コストがかかるため、呼び出すたびにコンパイルするのではなく、生成されたデリゲートをキャッシュして再利用してください。
using System;
using System.Linq.Expressions;
Expression<Func<int, int>> tree = x => x * x;
var square = tree.Compile(); // compile once
for (int i = 1; i <= 3; i++)
Console.Write(square(i) + " "); // 1 4 9
Console.WriteLine();述語を動的に構築する
一般的な用途の 1 つは、ユーザー入力から実行時にフィルター述語を構築し、それを Func にコンパイルすることです。
using System;
using System.Linq.Expressions;
var n = Expression.Parameter(typeof(int), "n");
var isPositive = Expression.GreaterThan(n, Expression.Constant(0));
var pred = Expression.Lambda<Func<int, bool>>(isPositive, n).Compile();
Console.WriteLine(pred(5)); // True
Console.WriteLine(pred(-2)); // False条件を組み合わせる
コンパイル前に Expression.AndAlso / OrElse を使って述語を組み合わせます。
using System;
using System.Linq.Expressions;
var n = Expression.Parameter(typeof(int), "n");
var inRange = Expression.AndAlso(
Expression.GreaterThanOrEqual(n, Expression.Constant(1)),
Expression.LessThanOrEqual(n, Expression.Constant(10)));
var fn = Expression.Lambda<Func<int, bool>>(inRange, n).Compile();
Console.WriteLine(fn(5) + " " + fn(11)); // True False計算式をコンパイルする
実行時に算術式を組み立てることもできます。これはルールエンジンや計算機に役立ちます。
using System;
using System.Linq.Expressions;
var p = Expression.Parameter(typeof(double), "p");
// price * 1.2 (add 20% tax)
var withTax = Expression.Multiply(p, Expression.Constant(1.2));
var calc = Expression.Lambda<Func<double, double>>(withTax, p).Compile();
Console.WriteLine(calc(100)); // 120型指定のないラムダ式に DynamicInvoke を使う
ジェネリックではない Expression.Lambda を使用した場合は、Delegate にコンパイルして DynamicInvoke を呼び出します。
using System;
using System.Linq.Expressions;
var x = Expression.Parameter(typeof(int), "x");
var body = Expression.Add(x, Expression.Constant(10));
Delegate d = Expression.Lambda(body, x).Compile();
Console.WriteLine(d.DynamicInvoke(5)); // 15パフォーマンスに関する注意
コンパイル済みの式は、1 回コンパイルした後はおおむねデリゲートと同じ速度で実行されます。頻繁に実行される処理では、起動時に 1 回だけコンパイルしてデリゲートを保存してください。
using System;
using System.Linq.Expressions;
Expression<Func<int, int>> tree = x => x + x;
var doubler = tree.Compile();
int total = 0;
for (int i = 0; i < 5; i++) total += doubler(i);
Console.WriteLine(total); // 0+2+4+6+8 = 20コンパイル時にエラーが表面化する
ツリーの形式が不正な場合(パラメーターが不足している場合など)、Compile() は例外をスローします。そのため、ツリーを利用する前に検証してください。
using System;
using System.Linq.Expressions;
var x = Expression.Parameter(typeof(int), "x");
var y = Expression.Parameter(typeof(int), "y");
try {
// body references y but lambda only declares x
var lambda = Expression.Lambda<Func<int, int>>(Expression.Add(x, y), x);
lambda.Compile();
} catch (InvalidOperationException) {
Console.WriteLine("unbound parameter");
}まとめ
小さな計算式を 1 つの流れで構築、コンパイル、実行します。
using System;
using System.Linq.Expressions;
var x = Expression.Parameter(typeof(int), "x");
var formula = Expression.Add(
Expression.Multiply(x, Expression.Constant(2)),
Expression.Constant(3)); // 2x + 3
var fn = Expression.Lambda<Func<int, int>>(formula, x).Compile();
Console.WriteLine(fn(4)); // 11クイックチェック
式ツリーを実行する方法を確認します。
まとめ
式ツリーをコンパイルして実行する方法を学びました。
Compile()は、ツリーを呼び出し可能なデリゲートに変換します。- コンパイルには 1 回限りのコストがかかるため、デリゲートをキャッシュします。
- 述語や計算式を動的に構築してからコンパイルできます。
- 形式が不正なツリーは
Compile()で例外をスローします。
よくある質問
「式のコンパイルと実行」レッスンは無料ですか?
はい。「式のコンパイルと実行」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「式のコンパイルと実行」で何を学びますか?
式ツリーを実行可能なデリゲートに変換します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「式のコンパイルと実行」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 式ツリーとは
- 式の手動構築
- 式のコンパイルと実行
- LINQプロバイダーにおける式ツリー