Я пишу «фабрику слабых событий» - код, который преобразует любого делегата в нового делегата с идентичной подписью, но с реализацией WeakReference на цели. Я использую MSIL, чтобы избежать вызовов Delegate.CreateDelegate (производительность которых оказалась низкой).
Слабые ссылочные делегаты работают идеально до тех пор, пока базовый метод (Method исходного делегата) объявлен общедоступным. Как только будет использован частный или анонимный метод, 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);
Так в чем же секрет вызова частного члена? Отражение может это сделать, деревья выражений могут это сделать ... почему приведенный выше код не работает?
РЕДАКТИРОВАТЬ: Большое спасибо всем, кто дал здесь ответы. Оказывается, единственным решением, которое последовательно работало в моем контексте, было использование универсальных делегатов (Action) ... поскольку Action исходит из mscorlib, JIT кажется вполне счастливым, позволяя ему вызывать частный метод . попробуйте использовать своего собственного делегата, и JIT рвет точно так же, как если бы вы посылали Call или Callvirt прямо к цели.
Любой, кто хочет увидеть рабочий код, может перейти к codeplex - ответы, приведенные здесь, помогли реализовать возможности WeakDelegate. .