私は「弱いイベントファクトリ」を書いています。これは、任意のデリゲートを同じ署名を持つ新しいデリゲートに変換するコードですが、ターゲットにWeakReferenceを実装しています。私はMSILを使用して、Delegate.CreateDelegateの呼び出しを回避しています(パフォーマンスが遅いことが示されています)。
弱参照デリゲートは、基になるメソッド(元のデリゲートのメソッド)がパブリックであると宣言されている限り、完全に機能します。プライベートメソッドまたは匿名メソッドが使用されるとすぐに、MSILは実行時にMethodAccessExceptionで爆撃します。
コンパイルされた式ツリーを使用して、プライベートメソッドを呼び出すことができたので、プライベートメソッドを呼び出すMSILを動的に発行できる必要があります。...では、次の何が問題になっていますか?
// var target = this.Target
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, targetPropGetter);
il.Emit(OpCodes.Stloc, ilTarget);
// if(target != null)
// {
il.Emit(OpCodes.Ldloc, ilTarget);
il.Emit(OpCodes.Brfalse_S, ilIsNullLabel);
// Method( @target, parm1, parm2 ...);
il.Emit(OpCodes.Ldloc, ilTarget); // this = Target
short argIndex = 1;
foreach (var parm in delgParams) // push all other args
il.Emit(OpCodes.Ldarg, argIndex++);
il.Emit(OpCodes.Callvirt, delegat.Method); // <-- Bombs if method is private
il.Emit(OpCodes.Ret);
// }
il.MarkLabel(ilIsNullLabel);
では、プライベートメンバーを呼び出す秘訣は何ですか?リフレクションはそれを行うことができます、式ツリーはそれを行うことができます...なぜ上記のコードは失敗するのですか?
編集:ここで答えを提供してくれたすべての人に感謝します。私のコンテキストで一貫して機能した唯一の解決策は、ジェネリックデリゲート(アクション)を使用することでした...アクションはmscorlibから発生するため、JITはプライベートメソッドを呼び出せるように完全に満足しているようです。独自のデリゲートを使用してみてください。JITは、ターゲットに直接CallまたはCallvirtを発行する場合とまったく同じように実行します。
動作するコードを確認することに興味がある人は誰でも、 codeplexにアクセスできます。ここに記載されている回答は、WeakDelegate機能の実装に役立ちました。