你如何从MSIL调用私有方法?

我正在编写一个“弱事件工厂” - 将任何代表转换为具有相同签名的新代表的代码,但是要在目标上实现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);

那么调用私人会员的秘诀是什么? 反射可以做到这一点,表达式树可以做到这一点...为什么上面的代码失败?


编辑:非常感谢你在这里提供答案的所有人。 事实证明,在我的上下文中一直工作的唯一解决方案是使用泛型委托(Action)...因为Action来自mscorlib,JIT似乎非常乐意让它调用私有方法。 尝试使用自己的代理和JIT智能卡,就像直接向目标发送Call或Callvirt一样。

任何有兴趣看到工作代码的人都可以前往codeplex--这里给出的答案有助于实现WeakDelegate功能。


你是将你的IL插入DynamicMethod还是动态组装的方法中? 据我了解,无法从动态程序集中跳过可见性检查,但在使用DynamicMethod时可以跳过它们(请参见此处)。


解决方案(针对我的特定问题)是使用委托而不是直接方法调用。 您可以轻松地构造一个开放委托并将其传递给IL代码,然后当IL代码调用委托的Invoke方法时,JIT接受该模式为合法,并允许调用私有方法。

就像我说的,这是一个解决方案(它很高兴地允许运行时生成的代码调用私有方法),尽管它仍然不能解释表达式树和反射等技术如何管理调用私有方法。


我只是st upon于这个线程找到一个解决方案,以'为我的特殊情况闯入非公共方法',所以关于上述选项(IL生成,编译表达式树),它们将工作在我的情况下,还是它绝望?

我只想调用RuntimeMethodInfo.InternalGetCurrentMethod(...),传递我自己的参数(这样我就可以实现GetCallingMethod(),或者直接在我的日志例程中使用RuntimeMethodInfo.InternatGetCurrentMethod(StackCrawlMark.LookForMyCaller)。GetCurrentMethod的实现方式如下:

[MethodImpl(MethodImplOptions.NoInlining)]
public static MethodBase GetCurrentMethod()
{
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller);
}

其中声明了InternalGetCurrentMethod:internal :-)。

我没有任何问题使用反射来调用方法,但是这会弄乱调用堆栈,这只是必须保留的一件事,否则它会失败它的目的。

使用任何所讨论的方法,我的堆栈跟踪接近原始数据的可能性是什么(至少在允许的StackCrawlMarks的范围内,它们是LookForMe,LookForMyCaller和LookForMyCallersCaller)?

链接地址: http://www.djcxy.com/p/36061.html

上一篇: how do you invoke a private method from MSIL?

下一篇: Why is debugging better in an IDE?