ハンズオン勉強会、Hokuriku.NET C# メタプログラミング ~リフレクション~に参加しました。その中で、アセンブリの動的読み込みをする時間がありました。参照設定に加えられていないアセンブリに含まれているクラスのインスタンスを作る、というものです。その時間ちょっとハデ目にFormを出して遊んでみたので、その時のコードを紹介します。
やってみたこと
全体としては次のようなことやってみました。
- コンソールアプリのプロジェクトで開始する
- 参照設定なしでFormを表示する
- Formの上にボタンを配置する
- ボタンがクリックされたら、コンソール画面上に文字を表示する
こんな他愛もないことをコンソールアプリのプロジェクトでやる辺りに自己満足感があるということで...。
サンプルコード & 実行例
以下がそのサンプルコードです。動的に作成したインスタンスはobject型として返される上、(参照設定を入れていないので)型変換もできないので、PropertyInfo / MethodInfo / EventInfoをガリガリ使って値を設定します。今回はリフレクションなお題ということで使っていませんが、dynamicを使えばもう少し楽に書くことができます。
using System; using System.Reflection; namespace ShowFormDynamically { class Program { static void Main() { //--- Formsアセンブリ読み込み var assembly = Assembly.LoadFile(@"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.5\\System.Windows.Forms.dll"); //--- Buttonを生成 var button = assembly.CreateInstance("System.Windows.Forms.Button"); //--- Buttonに表示する文字を設定 button.GetType().GetProperty("Text").SetValue(button, "Click here!!"); //--- Buttonのクリックイベントを設定 EventHandler handler = (sender, e) => Console.WriteLine("クリックしたー"); button.GetType().GetEvent("Click").AddEventHandler(button, handler); //--- Buttonを親コントロールにFill Docking var dockStyleType = assembly.GetType("System.Windows.Forms.DockStyle"); var fill = Enum.Parse(dockStyleType, "Fill"); button.GetType().GetProperty("Dock").SetValue(button, fill); //--- Formインスタンスを生成 var form = assembly.CreateInstance("System.Windows.Forms.Form"); //--- Formのキャプションを設定 form.GetType().GetProperty("Text").SetValue(form, "Viva Reflection!!"); //--- ButtonをFormに乗せる var controls = form.GetType().GetProperty("Controls").GetValue(form); controls.GetType().GetMethod("Add").Invoke(controls, new object[]{ button }); //--- 起動! form.GetType().GetMethod("ShowDialog", Type.EmptyTypes).Invoke(form, null); } } }
結果は次のようになります。ボタンをクリックすると、ちゃんとコンソール画面に文字列が表示されます。
まとめ
リフレクションはちょっとした奥義みたいなものです。上記のようなジョークはさて置き、サードパーティ製ライブラリのprivateやinternalなプロパティから値を無理やり取得したりなんてこともできます。実行速度がすこぶる悪いので多用は禁物ですが、利用する目的を明確にして採用したいところです。
たまにこうやってリフレクション脳を鍛えるようにすると、いざというときに役立つかもしれません。
その他の参加者レポート
Hokuriku.NET C# メタプログラミング ~リフレクション~ 感想
[C#][dynamic] リフレクション Q&A