-
Notifications
You must be signed in to change notification settings - Fork 0
MS_ExpressionTree
- 式木(Expression tree)とは、式(数式)を木構造で表したものの事。
- 以前は、1 文だけのラムダ式のみ式木(Expression tree)にできた。
- .NET 4 から、強化され DLR で使っている構文木の全機能を備える。
補足(何が嬉しいのか): 通常、ラムダ式は
**コンパイルされてデリゲート(実行可能なコード)**になる。
式木は、それを **「コードの構造そのもの(データ)」**として保持する。// ① デリゲート:実行できるが、中身は覗けない Func<int, bool> f = x => x > 5; // ② 式木:実行できないが、構造を解析できる Expression<Func<int, bool>> e = x => x > 5;
eは次のような木になっている。BinaryExpression (GreaterThan) ├── ParameterExpression (x) └── ConstantExpression (5)この「構造を読める」という性質から、次の 2 つの使い道が生まれる。
用途 内容 別の言語へ翻訳する 木を辿って SQL を組み立てる(LINQ プロバイダ) コードを生成して高速化する 木を組み立てて Compile()し、デリゲートにするなお、
Expression<T>はCompile()でデリゲートに変換できるが、
逆(デリゲート → 式木)はできない。
実際に、文字列の計算式の計算結果を取得するライブラリでは、
RPN(Reverse Polish Notation、逆ポーランド記法)や
式木(Expression Tree)を使って計算するライブラリなどがある。
補足(
eval相当が .NET に無い理由): JavaScript のevalや
Python のevalに相当するものが .NET の標準にはない
(静的型付け言語であり、実行時にコンパイラを持たないため)。このため「文字列の数式を計算する」には、
- 自前で構文解析して RPN に変換し、スタックで評価する、
- 式木を組み立てて
Compile()する(何度も評価するなら速い)、- Roslyn Scripting API(
Microsoft.CodeAnalysis.CSharp.Scripting)を使う、という選択肢がある。3 は C# のコードをそのまま実行できるが、
コンパイラを丸ごと抱えることになるため重い(.NETコンパイラ)。
LINQプロバイダでは、ラムダ式を式木として扱う
補足(
IEnumerableとIQueryableの分岐点): LINQ には
2 つの入口があり、式木を使うかどうかがその違いである。
IEnumerable<T>(LINQ to Objects)IQueryable<T>(LINQ to SQL/EF)引数の型 Func<T, bool>(デリゲート)Expression<Func<T, bool>>(式木)評価場所 メモリ上で 1 件ずつ評価 木を SQL に翻訳して DB 側で評価 結果 全件取ってから絞る DB で絞ってから取る // ① IQueryable:WHERE 句に翻訳され、DB 側で絞られる db.Users.Where(u => u.Age > 20).ToList(); // ② AsEnumerable() を挟むと…全件取得してからメモリで絞る db.Users.AsEnumerable().Where(u => u.Age > 20).ToList();② は結果は同じだが、テーブル全件がアプリに流れてくる。
EF Core での性能事故の典型がこれで、
「なぜ式木なのか」を理解していないと踏みやすい。また、式木として翻訳できないメソッド(自作メソッドなど)を
Whereの中で呼ぶと、EF Core では実行時に例外になる
(EF6 までは暗黙にクライアント評価へフォールバックしていたが、
事故のもとであったため EF Core 3.0 で既定で例外に変わった)。
-
herara_ofnir3.blogger: [C#]式木入門
http://ofnirs.blogspot.com/2012/11/introduction-of-expression-tree.html- 全てが式になる,全てが木になる,全てが式木になる - NyaRuRuが地球にいたころ
http://nyaruru.hatenablog.com/entry/20071230/p1 - 式木(Expression Trees) - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
https://ufcpp.net/study/csharp/sp3_expression.html
- 全てが式になる,全てが木になる,全てが式木になる - NyaRuRuが地球にいたころ
-
文字列の計算式の計算結果を取得する - .NET Tips (VB.NET,C#...)
https://dobon.net/vb/dotnet/programing/eval.html- C# Expression Parser using RPN - CodeProject
https://www.codeproject.com/Articles/5875/C-Expression-Parser-using-RPN - 逆ポーランド記法と木構造の絵
https://qiita.com/yumura_s/items/ddb0d143fb0e9a082891
- C# Expression Parser using RPN - CodeProject
-
LINQとの関連
- C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
https://www.slideshare.net/Fujiwo/20141026-c-c-expression-tree - [C#][式木][LINQ] IQueryable な Twitter のタイムライン クラスと
LINQ プロバイダー (プログラミング C# - 翔ソフトウェア (Sho's))
http://blog.shos.info/archives/2014/12/csharp_expression_iqueryable.html
- C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
-
neue cc - Expression Treeのこね方・入門編 - 動的にデリゲートを生成してリフレクションを高速化
http://neue.cc/2011/04/20_317.html
(プログラミング C# - 翔ソフトウェア (Sho's))
Expression として扱えるラムダ式と扱えないラムダ式
http://blog.shos.info/archives/2012/11/cexpression_expression.html
- Expression の構造を調べてみる
http://blog.shos.info/archives/2012/11/cexpression_expression_1.html - Expression を使ってラムダ式のメンバー名を取得する
http://blog.shos.info/archives/2012/12/cexpression_expression_2.html - Expression でラムダ式を作成してデリゲートとして実行する
http://blog.shos.info/archives/2013/06/csharp_expression4.html
メタプログラミング入門
- 式木による Add メソッドの動的生成
http://blog.shos.info/archives/2013/11/csharp_addbyexpression.html - 応用編 - オブジェクトの文字列変換のメタプログラミング (式木編)
http://blog.shos.info/archives/2013/11/csharp_metaprogrammingpraxisexpression.html
Tags: 移行, プログラミング, .NET開発
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。