初回からナンですが、今回の話の中心は CodeDOM であって、リフレクションは最後のほうに少し出るだけです。次回以降は、リフレクションを主体にする予定ですが、これも「例」のひとつとして参考にしていただけたらと思います。
.NET には、実行時に外部のソース ファイルをコンパイルし、実行可能ファイルやアセンブリを生成するためのクラスが用意されています。今回は VB .NET で書かれたソース ファイルから、アセンブリを生成する方法について説明します。まず、TestClass.vb というファイルに、次のような実験用クラスを定義します。
Imports System Public Class TestClass Public Function GetMessage() As String Return "メッセージ" End Function End Class
次に、適当なコンソール プロジェクトを作り、以下のコードを貼り付けてください。コード中の ..\TestClass.vb の部分は、実際に TestClass.vb を置いているパスに書き換えてください。このコードではプロジェクトと同じフォルダにあると仮定しています。
Imports System.Reflection Imports System.CodeDom.Compiler Module Module1 Sub Main() Dim vbc As ICodeCompiler = (New VBCodeProvider).CreateCompiler() Dim param As New CompilerParameters Dim result As CompilerResults = vbc.CompileAssemblyFromFile( _ param, "..\TestClass.vb") If result.NativeCompilerReturnValue = 0 Then Dim asm As [Assembly] = result.CompiledAssembly Dim obj As Object = asm.CreateInstance("TestClass") Console.WriteLine(obj.GetType().GetMethod("GetMessage"). _ Invoke(obj, Nothing)) Else Console.WriteLine("Failed to compile.") End If Console.WriteLine("Enter を押すと終了します。") Console.ReadLine() End Sub End Module
実行結果
メッセージ Enter を押すと終了します。
Main の上部3行の意味については、クラスやメソッドの名前からして自明なので、CompilerParameters と CompilerResults の用法について説明したいと思います。CompilerParameters の用法は、名前のとおりコンパイルのパラメータを設定するものなのですが、そのひとつに「出力先の指定」というものがあります。上記コードのように出力先を指定しない場合は、一時ファイルを保存するフォルダに、ランダムな名前の DLL が作成されます。ファイル名を限定したい場合は、OutputAssembly プロパティに名前を設定します。また、ファイルとして生成されると問題がある場合、GenerateInMemory プロパティを True にします。文字どおりメモリ上に生成されます。DLL でなく EXE を生成したい場合は、プログラムのいずれかのクラスにエントリ ポイントを追加し、GenerateExecutable プロパティを True にします。
ところで今回は String しか使いませんでしたが、自分で別途作成したアセンブリのクラスを使用したい場合はどうすればいいのでしょうか。その場合は ReferencedAssemblies プロパティに、参照させたいアセンブリの名前を追加すると使用できるようになります。これは IDE のメニューから「参照の追加」を選び、参照するアセンブリを追加するのと同じことです。また、コンパイラを呼び出すアセンブリに定義されているクラスを使用したい場合、ReferencedAssemblies に自身のパスを追加し、完全限定名で型を指定することで使用可能になります。「参照の追加」では EXE を指定できませんが、こちらでは指定できます。
次に CompilerResults について説明します。コンパイルの成否は、NativeCompilerReturnValue プロパティの値で判断します。MSDN ライブラリによれば、0 であれば成功、それ以外はすべて失敗だそうです。いずれの場合でも、Output プロパティにメッセージが出力されます。失敗した場合は Errors プロパティを参照してください。成功した場合は、CompiledAssembly プロパティにアセンブリへの参照が設定されます。
アセンブリを生成したら、コンストラクタやメソッドへの参照を取得し、呼び出します。これを詳しく扱うと今回のテーマの範囲を超えるので、簡単なコードを掲載するだけにしました。説明は省略します。ちなみにファイルとしてアセンブリを生成した場合、自動的には削除されません。一時ファイルを保存するフォルダに、アルファベットの小文字、数字、アンダー スコアをランダムに組み合わせた8文字の名前をもつ DLL があるはずです。不都合があれば削除してください。
この方法による動的コンパイルは、C# で書かれたソースに対しても同様に行なうことができます。もちろん vbc.exe や csc.exe を起動してコンパイルしてもよさそうですが(実際、CompileAssemblyFromFile メソッドはこれらのプログラムを起動しているようですが)、パラメータをプロパティとして設定できるとか、出力を文字列のコレクションとして得られるなど、色々と便利なこの方法を用いることを推奨します。