私の質問はこれです:
ConstructorInfo.Invoke呼び出しに対応するDynamicMethodオブジェクトを構築する場合、すべての (またはほとんどの) 型の引数に対処するには、どの型の IL を実装する必要がありますか?呼び出しを行う前に、引数の数が渡されますか?
バックグラウンド
私は IoC コンテナーの 3 回目の反復を行っており、現在、使用されている大量の時間を簡単に削減できる領域があるかどうかを把握するために、いくつかのプロファイリングを行っています。
私が気づいたことの 1 つは、具象型に解決するときに、最終的にConstructorInfo.Invokeを使用してコンストラクターが呼び出され、解決した引数の配列を渡すことになるということです。
私が気づいたのは、invoke メソッドにはかなりのオーバーヘッドがあるということです。これのほとんどは、私が行っているのと同じチェックの別の実装にすぎないのではないかと考えています。
たとえば、コードに一致するコンストラクターがあるため、渡した定義済みのパラメーター名、型、および値に一致するコンストラクターを見つけるために、この特定の呼び出し呼び出しができるはずのもので終わらない方法はありません。適切な数の引数、適切な順序、適切な型、および適切な値に対処するためです。
解決メソッドへの 100 万回の呼び出しを含むプロファイリング セッションを実行し、それを Invoke 呼び出しを模倣するDynamicMethod実装に置き換えると、プロファイリングのタイミングは次のようになりました。
- ConstructorInfo.Invoke: 1973ms
- ダイナミックメソッド: 93ms
これは、このプロファイリング アプリケーションの合計実行時間の約 20% を占めています。つまり、ConstructorInfo.Invoke 呼び出しを同じことを行う DynamicMethod に置き換えることで、基本的なファクトリ スコープのサービスを処理するときに 20% のランタイムを削減できます (つまり、すべての解決呼び出しはコンストラクター呼び出しで終了します)。
これはかなり重要なことであり、このコンテキストでコンストラクター用の安定した DynamicMethod ジェネレーターを構築するのにどれだけの作業が必要かを詳しく調べる必要があると思います。
したがって、動的メソッドはオブジェクト配列を受け取り、構築されたオブジェクトを返します。問題の ConstructorInfo オブジェクトは既にわかっています。
したがって、動的メソッドは次の IL で構成されるように見えます。
l001: ldarg.0 ; the object array containing the arguments
l002: ldc.i4.0 ; the index of the first argument
l003: ldelem.ref ; get the value of the first argument
l004: castclass T ; cast to the right type of argument (only if not "Object")
(repeat l001-l004 for all parameters, l004 only for non-Object types,
varying l002 constant from 0 and up for each index)
l005: newobj ci ; call the constructor
l006: ret
他に考慮すべきことはありますか?
アプリケーションを「アクセス制限モード」で実行している場合、動的メソッドの作成はおそらく利用できないことを認識していることに注意してください(脳がこれらの用語をあきらめない場合があります)が、その場合、それを簡単に検出して、オーバーヘッドとすべてを使用して、以前と同じように元のコンストラクターを呼び出します。