通过Emit(Opcodes.Call,methodinfo)创建一个类型的实例



我正在使用Reflection和ilGenerator创建一个.Exe,它从DLL中调用一个方法。

我的问题是,当它是一个实例方法时,我必须在调用该方法之前将实例放入堆栈中。因此,我在C#中有一个方法,它创建并返回这个实例。它正在抛出System.MethodAccessException

我的问题是,这可能吗?它是如何工作的?通过在IL、il.Emit(Opcodes.call, methodInfo)、创建.exe的调用中执行此操作,在运行时,它如何知道要调用什么方法?我要调用的方法是否转到.exe程序集?我对此感到非常困惑。

我转到DLL,获取类型,获取我要调用的MethodInfo。我创建了一个新的Assembly->AssemblyBuilder->ModuleBuilder->TypeBuilder我正在创建的这个新类型是从DLL扩展type:

 TypeBuilder tb = mb.DefineType("TypeApp" + typeName, baseType.Attributes, DLLType);

我创建MethodBuilder作为新类型的入口点

MethodBuilder metb = tb.DefineMethod("Main", MethodAttributes.Public |
            MethodAttributes.Static, typeof(void), argsArray);
ab.SetEntryPoint(metb);

然后我为Main方法生成IL:

ILGenerator il = metb.GetILGenerator();
il.Emit(OpCodes.Call, callcreateInstanceMethodInfo);

IL仍在继续,但到目前为止我还不完全理解…

然后我创建.exe

 tb.CreateType();
 ab.Save(typeName + methodName + ".exe");

它正在投掷System.MethodAccessException

你是否试图调用一个通常对你生成的类型不可见的方法(调用私有或内部方法,在你不继承的类中调用受保护的方法)。我相信禁用验证是可能的,但这会增加代码的安全要求,如果您需要在部分信任环境中运行,这是一个问题。

在创建.exe的调用中,在运行时,它如何知道要调用什么方法?

发出的IL包含一个4字节的元数据令牌,这本质上是对生成的模块中的一个元数据表(MethodDef或MemberRef表)中的记录的引用。如果它是MethodDef令牌,那么它是对方法定义的直接引用;如果它是MemberRef令牌,则它将提供足够的信息来标识要调用的正确程序集/类/方法。

显示的生成IL的代码表明您使用了调用操作码。如果您正在调用一个虚拟方法,那么您应该使用callvirt(尽管您可以对非抽象方法使用call,但它会导致调用特定的实现……即使它被重写,这也可能是意外的,我在某个地方读到,对另一个对象的虚拟方法使用call增加了安全性要求)。

相关内容

  • 没有找到相关文章

最新更新