web-dev-qa-db-ja.com

Reflection.EmitとCodeDOM

Reflection.Emitライブラリを使用することとCodeDOMを使用して実行時にコードを動的に生成することの長所/短所は何ですか?

XML形式で実行時に利用可能なメタデータに基づいて、システムでいくつかの(比較的複雑な)動的クラスを生成しようとしています。アプリケーションアセンブリの既存のクラスを拡張するクラスを生成し、追加のインターフェイスを実装し、メソッドを追加し、仮想メンバーと抽象メンバーをオーバーライドします。

実装に深く入り込む前に、適切な手法を選択していることを確認したいと思います。これらのさまざまなコード生成手法の違いに関する情報があれば役立ちます。また、いずれかのAPIでの作業を簡素化または合理化するオープンソースライブラリに関する情報も役立ちます。

51
LBushkin

CodeDOMとReflection.Emitの要点は次のとおりです。

  • CodeDomはC#ソースコードを生成し、通常、ソリューションの一部として含まれ、IDE(たとえば、LINQ to SQLクラス、WSDL、XSDはすべてこのように機能します)。このシナリオでは、部分クラスを使用して、生成されたコードをカスタマイズすることもできます。 C#ソースを生成し、コンパイラーを実行して(再び!)解析してコンパイルするため、効率は低下します。ループなどの比較的高レベルの構造(C#の式やステートメントと同様)を使用してコードを生成できます。

  • Reflection.EmitはILを生成するため、メモリにのみ保存できるアセンブリを直接生成します。その結果、はるかに効率的です。低レベルのILコードを生成する必要があります(値はスタックに格納されます。ループはジャンプを使用して実装する必要があります)。したがって、より複雑なロジックを生成することは少し困難です。

一般に、Reflection.Emitは通常、実行時にコードを生成するための好ましい方法と見なされますが、コンパイル時より前にコードを生成する場合はCodeDOMが推奨されます。シナリオでは、どちらもおそらく正常に機能します(ただし、CodeDOMは、実際には.NETインストールの一部であるC#コンパイラを呼び出す必要があるため、より高い特権が必要になる場合があります)。

別のオプションは、 Expression class を使用することです。 .NET 4.0では、C#式およびステートメントと同等のコードを生成できます。ただし、クラスを生成することはできません。したがって、これをReflection.Emitと組み合わせることができる場合があります(Expressionを使用して生成されたコードに実装を委任するクラスを生成するため)。シナリオによっては、完全なクラス階層が実際には必要ない場合もあります。多くの場合、Dictionary<string, Action>などの動的に生成されたデリゲートのディクショナリで十分です(もちろん、正確なシナリオによって異なります)。

59
Tomas Petricek

CodeDomを対象とするコードは、ILではなくC#コードを生成しているため、保守が容易になる傾向があります(ILよりも多くの人がC#を読むことができます)。さらに、CodeDomコードを間違えると、コンパイラエラーが発生します。無効なILを生成すると、致命的な例外またはクラッシュが発生します。

ただし、CodeDomはcsc.exeコンパイラを呼び出すため、コードを使用できるようにするのに少し時間がかかります。 Reflection.Emitを使用すると、コードをメモリに直接生成できます。

CodeDomはおそらくほとんどの場合問題ありません。 XmlSerializerとWinFormsデザイナーはそれを使用します。

16
Tim Robinson

ExpandoObject を確認することをお勧めします。ただし、これは.NET4.0のみです。

7
Vlad