業務アプリの「魔法の杖」:動的コンパイルで計算式を爆速実行する
こんにちは。現場で「動かないコード」を数多のコードレビューで救い上げてきた、あなたの頼れるエンジニアです。
皆さんは業務アプリを作っていて、こんな経験はありませんか?
「ユーザーがExcelのように自由に計算式を入力できるようにしたいけど、`If`文を延々と並べるのは嫌だ…」
「複雑な計算ロジックを、わざわざアプリの再コンパイルなしで反映させたい…」
そんな時、ほとんどの初心者は「文字列を解析する自作パーサー」を作ろうとして泥沼にハマります。しかし、VB.NETの神髄を知る私たちは「CodeDomProvider」という魔法の杖を使います。
今回は、ユーザーが入力した文字列を、その場でCPUが実行可能な機械語へ変換(コンパイル)し、高速実行する技術を伝授しましょう。
—
1. なぜ「動的コンパイル」なのか?
一般的な「文字列を解釈して計算するツール(インタプリタ)」は、実行のたびに「これは足し算かな? 引き算かな?」と文字列を解析します。これではパフォーマンスが悪く、複雑な計算には耐えられません。
一方、今回紹介する手法は、「ユーザーの計算式を、VB.NETのソースコードとして書き出し、それをコンパイルしてDLL(またはメモリ内アセンブリ)としてロードする」という方法です。
一度コンパイルしてしまえば、あとはアプリ内部のメソッドを呼ぶのと同等の速度で動きます。これがプロの選択です。
—
2. 実装の設計図
この仕組みは、大きく分けて以下の3ステップで動きます。
1. テンプレートの準備: 計算式を埋め込むための骨組み(クラス定義)を用意する。
2. コードの生成: ユーザーの入力値をテンプレートに流し込む。
3. コンパイルと実行: `CodeDomProvider`を使ってメモリ上でコンパイルし、反射(Reflection)で呼び出す。
準備するもの
プロジェクトの参照設定で `System.CodeDom` や `Microsoft.CodeDom.Providers.DotNetCompilerPlatform` が必要になる場合がありますが、基本的には標準ライブラリで完結可能です。
—
3. 実践:簡易計算エンジンコード
まずは、動的にコンパイルされるクラスのテンプレートです。
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports Microsoft.VisualBasic
Public Class DynamicCalculator
‘ ユーザーの式を動的にコンパイルする関数
Public Function CompileAndRun(formula As String, x As Double) As Double
Dim provider As New VBCodeProvider()
Dim cp As New CompilerParameters()
‘ メモリ上に作成(物理的なDLLファイルは作らない)
cp.GenerateInMemory = True
cp.GenerateExecutable = False
cp.ReferencedAssemblies.Add(“System.dll”)
‘ 動的に生成するコード(ここが肝!)
Dim sourceCode As String = $@”
Public Class Evaluator
Public Function Calculate(x As Double) As Double
Return {formula}
End Function
End Class”
‘ コンパイル実行
Dim cr As CompilerResults = provider.CompileAssemblyFromSource(cp, sourceCode)
‘ エラーチェック(ここを怠るとデバッグが地獄になります)
If cr.Errors.Count > 0 Then
Throw New Exception(“式が不正です: ” & cr.Errors(0).ErrorText)
End If
‘ 反射を使ってメソッドを呼び出す
Dim assembly As Assembly = cr.CompiledAssembly
Dim type As Type = assembly.GetType(“Evaluator”)
Dim obj As Object = Activator.CreateInstance(type)
Dim method As MethodInfo = type.GetMethod(“Calculate”)
Return CDbl(method.Invoke(obj, New Object() {x}))
End Function
End Class
—
4. このコードの「ここがすごい!」
- テンプレート構造: `Return {formula}` の部分に、ユーザーが入力した「x 1.08 + 500」といった式がそのまま埋め込まれます。
- メモリ上での実行: ハードディスクにファイルを書き込まないため、セキュリティ的にもクリーンで、動作も高速です。
- 強力な型安全性: 一度コンパイルされるとVB.NETの型チェックが働くため、実行時に予期せぬ型エラーで落ちるリスクが減ります。
—
5. 陥りやすい罠と対策
初心者がここでよくやる失敗は、「エラーハンドリングの欠如」です。
1. 式の構文エラー: ユーザーが「x + 5」のように入力した場合、`cr.Errors.Count` で必ず検知してください。ここをスキップすると、実行時にクラッシュします。
2. セキュリティリスク: この手法は強力ですが、「ユーザーにコードを書かせる」ことと同義です。信頼できない環境では、実行するユーザーの権限を制限するなどの対策が必須です。
3. オブジェクトの破棄: 大量に計算を行う場合、毎回`CompilerParameters`を生成するとメモリリークの原因になります。頻繁に呼ぶ場合は、コンパイル済みのメソッドをキャッシュして使い回しましょう。
—
最後に:エンジニアとしての一歩先へ
「文字列を処理する」という段階から「コードそのものを生成して制御する」という視点を持つと、VB.NETという言語の見え方がガラリと変わります。
最初は難しく感じるかもしれませんが、この `CodeDomProvider` を使いこなせるようになれば、あなたの作る業務アプリは「単なる入力フォーム」から「自分自身で進化するエンジン」へと変貌を遂げます。
ここをクリアすれば、あなたはもうただの初学者ではありません。さあ、次はどんな機能を自動化しますか? 応援していますよ!
