dav*_*v_i 4 c# cil reflection.emit
我正在尝试生成以下类:
public class MyType
{
public string MyMethod() { return "Hi"; }
}
Run Code Online (Sandbox Code Playgroud)
我的Emit代码如下:
var assemblyBuilder = GetAssemblyBuilder("MyAssembly");
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public, typeof(string), new Type[] { });
var ilBuilder = methodBuilder.GetILGenerator();
ilBuilder.Emit(OpCodes.Nop);
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Stloc_0);
ilBuilder.Emit(OpCodes.Br_S);
ilBuilder.Emit(OpCodes.Ldloc_0);
ilBuilder.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();
Run Code Online (Sandbox Code Playgroud)
但是当我调用MyMethod一个实例时,MyType我得到一个InvalidProgramException:Common Language Runtime检测到一个无效的程序.
我已经尝试将返回类型更改为void并使用just EmitWriteLine和Emit(OpCodes.Ret),运行正常,所以它必须是我在这里写的IL.
我错过了一些明显的东西吗?一个明确的解释将有所帮助,因为我刚刚开始使用Emit.
评论中的其他信息:
"原始"IL取自LINQ-pad中的IL-generation.
除了删除@KendallOpCodes.Br_S指出的内容之外,还需要声明要存储的局部变量"Hi":
ilBuilder.DeclareLocal(typeof(string));
ilBuilder.Emit(OpCodes.Nop);
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Stloc_0);
ilBuilder.Emit(OpCodes.Ldloc_0);
ilBuilder.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
另外,我认为整个事情可以缩短为(如果你使用编译器优化来构建你的类,这就是你得到的):
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
(只需加载字符串,将其放在评估堆栈的顶部,然后返回字符串).
如果你想复制关闭编译器优化的版本,我认为这是你最初尝试做的事情:
Label returnLabel = ilBuilder.DefineLabel();
ilBuilder.DeclareLocal(typeof(string));
ilBuilder.Emit(OpCodes.Nop);
/* Load the string "HI" and put it on the evaluation stack. */
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
/* Store "Hi" in the local variable we declared. */
ilBuilder.Emit(OpCodes.Stloc_0);
/* Jump to the return label, which is, err the next line anyway: */
ilBuilder.Emit(OpCodes.Br_S, returnLabel);
/* Mark "returnLabel" here so we can jump to it: */
ilBuilder.MarkLabel(returnLabel);
/* Load the contents of our local variable, put it on the evaluation stack: */
ilBuilder.Emit(OpCodes.Ldloc_0);
/* Return "Hi", which is now back on top of the evaluation stack: */
ilBuilder.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
您需要定义要分支的标签(使用ILGenerator.DefineLabel,使用MarkLabel,然后Emit在发出时将该标签传递给它)OpCodes.Br_S.
正如你所看到的那样,分支对于这种简短的方法来说毫无意义.
| 归档时间: |
|
| 查看次数: |
228 次 |
| 最近记录: |