しばらく時間が経ちましたが、満足のいく回答を読んでいないので、過去に行ったことを書きます。私が達成したことは理想的ではないと感じており、私自身ももっとうまくやりたいと思っているので、他のアプローチにも非常に興味があります。
過去数年間、「強化された」クラスのコード生成について、リストされている 4 つのアプローチのうち 3 つを試しました。
- Reflection.Emit
- T4
- CodeDom (ただし、これは私のプロジェクトの時点で完全ではなかったので、早い段階で破棄しました!)
プラス他の 3 つ:
一般に、私はこれらすべてのツールを調査して、OP の例に似たものから始めて、AOP の方法でコードの「織り」を取得しました。属性「特別」でタグ付けされたクラスとメソッドを作成し、それらの動作を変更します。私の最初のプロジェクトの時点では、C# の AOP ソリューションは十分に成熟していませんでした (ただし、これはその間に変更された可能性があります)。そのため、たとえば PostSharp については何も言えません。前述したように、私の目的は非常に似ていました。クラスとメソッドの属性に基づいて、追加のコード (およびクラス メンバーも) をクラスに追加します。プロトタイプに Reflection.Emit を使用し、最終的に Profiler API を使用して IL 書き換えを終了しました。
最終的に T4 を使用することになった 2 番目のプロジェクトは、少し異なりました。すでにコード ジェネレーター (より具体的にはパーサー ジェネレーター) を使用していましたが、生成されたソース コードをさらに (自動的に!) 修正する必要がありました。
Reflection.Emit
私は次のアプローチを使用しました: クラス (MakeProxy と呼びましょう) が特定のアセンブリをウォークし、属性を検索してから、新しい dll (「プロキシ」) を発行し、内部で元のアセンブリを呼び出し、目的のインターフェイスと動作を提供します。ユーザーに。
私は実際に、.NET 実行可能ファイルであるツールでクラスを使用しました。このツールは、コンパイル パスの後に MS Build によって実行されました。
主な欠点: 参照の扱いが難しい場合があります。自動生成された dll を参照する必要があるため、コードを別のプロジェクトに分割する必要があり、ソリューションで元のプロジェクトを参照することさえできません... 受け入れられない場合があります。また、生成されたコードではなく、元のコードも (IDE で) 「見る」ことができます。これにより、デバッグが困難になる場合があります。
プロファイラ API
この場合、Reflection.Emit の場合と同じ作業を行いますが、「プロキシ」を事前に構築する必要はありません。コードは IL の生成時に挿入されます (つまり、1 回で、パフォーマンスの点で非常に優れています)。(管理されていない) プロファイラー DLL を作成し、その下でプログラムを開始するだけです。あなたの「プロファイラー」は、どの関数が実行されたか (あるいは、どの関数が JIT されたか) を通知され、それに応じて行動することができます。
主な欠点: クラスの「構造」(メソッド、フィールドなど) を変更できない (簡単ではありません)。アンマネージ API を使用した IL の生成は非常に困難です (多くのことを処理する必要があり、問題が発生した場合のデバッグは本当に悪夢です!) 主な利点: 元のコードを変更する必要はありません (特に、呼び出し側 - これは、その特定のプロジェクトの要件を考えると、最終的にこのソリューションに私を導いたものです)。
T4
別のプロジェクトで T4 を使用しましたが、ここで調査結果を共有できます。テキストの変換には適していますが、コードの変換には適していません。構文が「奇妙」になります(コードがあり、コードを生成するコードがコード内にあり、簡単に迷子になります)。
主な利点: IDE およびビルド システムとうまく統合されています。あなたはインテリセンスのサポートを受けます。始めるのは簡単です。実際にデバッグしているものを確認できます
個人的には、T4 のようなものを持ちたい (または自分で構築したい) のですが、それは C# -> C# コード変換を実行します。そうすれば、IDE の利点 (「元の」ものと「生成されたもの」の両方での IntelliSense を含む) と Reflection.Emit のパワーを利用できます。ただし、これらすべての機能を利用するには、おそらく C#/C# コンパイラと VS プラグインの両方をビルドする必要があります。
最後に 1 つ: 今日は、IKVM エミットやSigilなど、Reflection.Emit よりも「高度な」ものを使用します。