パターンが決まってるなら定型処理にしてしまえばいいじゃない。ユーティリティあるいはライブラリのようなものにしてみましょう。型の動的読み込みインスタンス/スタティックなメソッド呼び出し/プロパティ・フィールド書込/読取コンストラクタ呼出これらをSystem.Reflection名前空間のクラスを使って行うSystem.Linq.Expressionsのクラスを使って高速化してみるこの二本立てです。地味にボリューム重いです。型の動的読み込みさくさく行きましょう。言って方法は2パターン。System.Reflection.Assembly.GetTypeメソッドを使うか、System.Type.GetTypeメソッドを使うかです。false)ジェネリック型の動的読み込みちょっとメンドクサイのがジェネリック型。<'T>(※F#)とかついてるアレです。型引数に実際の型を当てはめて完成といった工程になります。ジェネリック引数を適用これで、System.Typeオブジェクトが取得できます。メソッド呼び出し手順はTypeオブジェクトからMethodInfoを探して取得するMethodInfoに「呼び出したいメソッドで使うインスタンス(staticメソッドならnull)」とメソッドの引数を渡すといった感じです。これでうまくいきそう?ちょっとここでストップです。}}中身は適当ですが、問題は「メソッド名と引数の数と順番が全て一致するメソッドが複数ある」場合です。このようなメソッドに対してGetMethodを呼び出すとどうなるか。困ったことに実行時エラーになります。手間はかかりますが、まとめて取得して条件で絞り込みましょう。0これで条件はBindingFlagsの適合メソッド名の一致ジェネリックか否かの一致(←大事!)パラメータの個数と型と順番が一致に増えます。ここまでやればたぶん大丈夫でしょう。速度が気になるのでメモ化しておきます。listに変わってるのはメモ化時に「リストの構造的等価」で比較してほしいからという問題が......あとはメソッド呼び出しだけですね。parametersの型がseq<obj*Type>なのは苦肉の策。引数の値とその型のペアのリスト、です。メソッド呼び出し手順は通常のメソッド呼び出しの手順が一個増えるだけです。paramsArray)プロパティ書込/読取こちらもやることはメソッドと大差ありません。TypeオブジェクトからPropertyInfoを取得するPropertyInfoに「書込/読取に使うインスタンス(staticメソッドならnull)」を渡してSet/Getといった感じです。こちらはジェネリックで重複が云々は......考えなくても大丈夫でしょう。instance全部のプロパティにアクセスしたいそういう話もありますよね。endフィールドは?PropertyInfoがFieldInfoになるだけでほとんどプロパティと変わらないので、コードだけ置いておきます。endコンストラクタこちらも同様、ConstructorInfoを取得して引数を渡して実行!というだけです。注意点としては、BindingFlagにInstanceを指定すると普通のコンストラクタが、Staticを指定すると「クラス初期化子」が取得される、ということです。使ってみるそろそろ実際のクラスに使ってみましょう。上記では省略していましたが、実際にはメソッド/プロパティ/フィールド/コンストラクタでそれぞれモジュールとして切り分けたものとして書いています。詳細は付録の実コードをご確認ください。//NG見たところそれっぽく動いてそうですね。letなフィールドがどうもエラーになるのが気になります。内部的にはどうなっているのでしょう。constの扱いの問題だと思うのですが......。式木?動的コード生成の魔境、式木(System.Linq.Expressions)編、スタートです。いっても触りだけ簡単に、それぞれのケースで****Infoから対応する式木を生成する程度にしておきます。メソッドMethodInfoから、対応する関数呼び出しを行うデリゲートを生成します。ex.Compile()ここで厄介なのが型引数'TFuncで、ここにはSystem.Func<...>やSystem.Action<...>を指定してやる必要があります。Expression.Lambda<'TFunc>のところで何も指定しないと、Compile()結果がSystem.Delegateになってしまい、DynamicInvokeしかできなくなってしまうので、高速化の意味ではちょっと微妙でしょう。(MethodInfoの内容から'TFuncを動的にロードしてやってもよさそうですが......諸事情により割愛。)プロパティメソッドができてしまえば、プロパティの方は一瞬で片付きます。プロパティはSetもGetもメソッドとして扱えるからです。propertyInfo.GetMethodフィールドフィールドはプロパティのようにラクできないので、地道に組み立てましょう。ex.Compile()コンストラクタ黙々と式木を組みます。ex.Compile()使ってみる同様に式木版も動かしてみます。薄い補助関数群を定義した程度なので、結局メンドクサイのは確かですね。dynamicキーワードで対応できないケース、例えば「呼び出すメソッド名の文字列を動的に指定したり」などは、こうして対応するしかありません。後はMethodInfo等をわずかでも触ろうと思えば厳しい。今回の全プロパティの値を列挙する処理などは、PropertyInfoの一覧を取る必要があります。testObj」などと並ぶ)ことには、実はある程度解決方法に目処が立っているのですが、諸事情により省略。実際そうらしいです(伝聞)。詳しくはSystem.Diagnostics.Stopwatchクラスでも使ってベンチマーク取りましょう。「初回呼び出し時にレスポンスを返しつつ、バックグラウンドでデリゲート生成」みたいなものも、作りかけましたが、諸事情により省略。呼び出すメソッド等の種類によって、ActionやFuncの型が違ってしまうのが困りものなんですよね。その辺をユーザに意識させない作りにできたら、使い勝手良いんじゃないかと思います......(今後の課題とします)。etc.)難しいことよくわかりません!「それF#でやる意味あるの?」F#だけで完結するプロジェクトなら、System.Reflectionよりは、Microsoft.FSharp.Reflectionの方を扱うことが圧倒的に多いと思います。クラスを定義するのもeasyな言語ですが、それ以上にタプルやレコード、判別共用体の適用範囲が広いためです。Frameworkや、その他(C#などで書かれた)ライブラリのクラスに対して使う場合。この場合はさほど有効とはいえないでしょう。privateやprotectedなフィールドにアクセスしに行く程度です。最後に、C#のプロジェクトから利用する場合。この場合はもうちょっと利用しやすさを考えてCompiledNameを付けたり拡張メソッドにしたり工夫が必要そうです。してみると「ならC#で書けば」と思いますが......しかしです、(↓続く)感想など「関数型言語でライブラリを書く」ということ自体は、かなりメリットがあるように感じました。不変な束縛や、容易な関数合成など、簡潔で保守性の高いコードを書ける環境がそろっています。今回はレコードや判別共用体までは持ち出しませんでしたけど、そのあたりも使い出がありそうです。http://neue.cc/2011/04/20_317.htmlメモ~化したりスマス。明日の記事は@bleisさんの「.NETの標準ライブラリと仲良くする話」です。2014の8日目の記事です。基礎プログラミング演習(1)プロフィールid:nenonoソフトウェアエンジニア。月別アーカイブはてなブログをはじめよう!nenonoさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。