LINQプロバイダーにおける式ツリー
プロバイダーが式をクエリに変換する仕組みを確認します。
「LINQプロバイダーにおける式ツリー」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
LINQ に式ツリーが必要な理由
LINQ には 2 つの形式があります。IEnumerable<T> はラムダ式をメモリ内で実行します。IQueryable<T> はラムダ式を式ツリーとして受け取り、プロバイダーが SQL などの別の言語に変換できるようにします。
IEnumerable と IQueryable の違い
違いはパラメーターの型にあります。IEnumerable.Where はコンパイル済みの Func<T,bool> を受け取るのに対し、IQueryable.Where はツリーである Expression<Func<T,bool>> を受け取ります。
using System;
using System.Linq;
using System.Linq.Expressions;
int[] nums = { 1, 2, 3, 4 };
// IEnumerable path: lambda is a compiled delegate
var evens = nums.Where(n => n % 2 == 0);
Console.WriteLine(string.Join(",", evens)); // 2,4クエリはデータのまま
IQueryable では、ラムダ式は式ツリーとして取得され、まだ実行されません。プロバイダーはツリーを調査してクエリを構築します。
using System;
using System.Linq;
using System.Linq.Expressions;
IQueryable<int> q = new[] { 1, 2, 3, 4, 5 }.AsQueryable();
var filtered = q.Where(n => n > 2);
Console.WriteLine(filtered.Expression.NodeType); // Call (a method-call tree)クエリ式を調査する
クエリ可能なオブジェクトの Expression プロパティを使うと、プロバイダーが変換するツリーを取得できます。
using System;
using System.Linq;
var q = new[] { 10, 20, 30 }.AsQueryable().Where(x => x >= 20);
Console.WriteLine(q.Expression.ToString().Contains("Where")); // True実行ではなく変換
Entity Framework のようなプロバイダーはツリーをたどり、WHERE Age > 18 のような SQL を生成します。C# の述語はクライアント上で実行されず、データベースが処理を行います。
IQueryProvider の役割
IQueryable は IQueryProvider を保持します。クエリを列挙すると、プロバイダーは式ツリーを受け取り、その実行方法を決定します。
using System;
using System.Linq;
var q = new[] { 1, 2, 3 }.AsQueryable();
Console.WriteLine(q.Provider.GetType().Name); // EnumerableQuery (the in-memory provider)遅延実行
ツリーが変換されて実行されるのは、列挙するとき(例: ToList、foreach)だけです。それまでは、自由に組み合わせられる純粋なデータとして保持されます。
using System;
using System.Linq;
var q = new[] { 1, 2, 3, 4 }.AsQueryable()
.Where(n => n > 1)
.Select(n => n * 10);
// nothing has run yet; now force it:
Console.WriteLine(string.Join(",", q.ToList())); // 20,30,40クエリを組み立てる
各演算子が式ツリーに追加されるため、クエリを段階的に構築できます。実行時には、プロバイダーが全体を確認できます。
using System;
using System.Linq;
var baseQuery = new[] { 5, 15, 25, 35 }.AsQueryable();
var q = baseQuery.Where(n => n > 10);
q = q.Where(n => n < 30); // composed: 10 < n < 30
Console.WriteLine(string.Join(",", q.ToList())); // 15,25変換できないもの
プロバイダーが変換できるのは、理解できる操作だけです。任意の C# メソッドを呼び出す述語は、SQL に相当するものがないため、実行時に例外をスローすることがあります。
独自のプロバイダーを作成する
カスタムプロバイダーは IQueryProvider を実装し、ExpressionVisitor を使ってツリーをたどり、各ノードを対象のクエリ言語に変換します。
まとめ
ここでの重要な点は、同じラムダ式が IEnumerable ではデリゲートになり、IQueryable では変換を可能にするツリーになることです。
using System;
using System.Linq;
using System.Linq.Expressions;
Expression<Func<int, bool>> predicate = n => n > 2;
var data = new[] { 1, 2, 3, 4 };
// IEnumerable needs a delegate:
Console.WriteLine(string.Join(",", data.Where(predicate.Compile()))); // 3,4
// IQueryable accepts the tree directly:
Console.WriteLine(string.Join(",", data.AsQueryable().Where(predicate))); // 3,4クイックチェック
LINQ プロバイダーで式ツリーが果たす役割を確認します。
まとめ
LINQ プロバイダーが式ツリーを使用する方法を学びました。
IEnumerableはコンパイル済みのFuncを使用し、IQueryableはExpression<Func>ツリーを使用します。- プロバイダーはツリーを実行するのではなく、SQL などに変換します。
- 実行は列挙するまで遅延されます。
- 変換可能な操作だけが機能し、任意のメソッドは失敗することがあります。
よくある質問
「LINQプロバイダーにおける式ツリー」レッスンは無料ですか?
はい。「LINQプロバイダーにおける式ツリー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「LINQプロバイダーにおける式ツリー」で何を学びますか?
プロバイダーが式をクエリに変換する仕組みを確認します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「LINQプロバイダーにおける式ツリー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 式ツリーとは
- 式の手動構築
- 式のコンパイルと実行
- LINQプロバイダーにおける式ツリー