我正在使用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增加了安全性要求)。