将本地加载到堆栈上以便在IL生成中进行方法调用?

时间:2011-09-28 23:19:46

标签: c# reflection reflection.emit il

我正在尝试生成IL来模仿以下方法MyMethod

public void DoSomething(object a, object b, string c, string d){...};
public virtual void MyMethod(object a, object b) 
{
    DoSomething(a, b, "hello", this.SomeInstanceString);
}

这是我到目前为止所做的,但是我无法理解将第3和第4个参数加载到堆栈上以调用DoSomething(a, b, "hello", this.SomeInstanceString))的正确方法:

 MethodBuilder myMethod = typeBuilder.DefineMethod("MyMethod",
    MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] 
       { typeof(object), typeof(object) });
 ILGenerator myMethodILGen = mbFromCustomObject.GetILGenerator();
 myMethodILGen.Emit(OpCodes.Ldarg_0);
 myMethodILGen.Emit(OpCodes.Ldarg_1);
 // How do I load the string "hello" and the local instance 
 // variable this.SomeInstanceString onto the stack?
 myMethodILGen.Emit(OpCodes.Call, GetMethodInfoForDoSomething());
 myMethodILGen.Emit(OpCodes.Ret);

那么,如何将字符串"hello"和本地实例变量this.SomeInstanceString加载到堆栈中以调用DoSomething

1 个答案:

答案 0 :(得分:4)

加载字符串文字非常简单。

myMethodILGen.Emit(OpCodes.Ldstr, "hello");

从对象实例加载字段要求您首先将对象实例加载到堆栈上,然后使用Ldfld操作码。你可能已经为你的SomeInstanceString字段设置了一个FieldBuilder,你可以用它。

FieldBuilder fieldBuilder = typeBuilder.DefineField(
                    "SomeInstanceString",
                    typeof(string),
                    FieldAttributes.Public);

myMethodILGen.Emit(OpCodes.Ldarg_0);
myMethodILGen.Emit(OpCodes.Ldfld, fieldBuilder);

另外,请记住,Ldarg_0 不会执行您认为的操作。实例方法有一个隐式参数,该参数位于零槽中,该参数包含该方法当前在其​​中运行的实例。这就是为什么我们使用Ldarg_0取消引用字段的原因,因为大概你想要方法所在的实例。但这不适用于静态方法。